qcacld-3.0: SAP DFS-3 channel selection suppport for 80+80MHz/160MHz

Add support for setting channel width for CSA and modify the
SAP DFS channel width fallback algoritham to support DFS for
80+80Mhz and 160Mhz bandwidth. Also, compile out channel matrix
restriction from channel selection process after radar
indication is received for newer platforms and only compile
for older platforms

Change-Id: I771fc162b18aa1e485c513046a265b2d94612972
CRs-Fixed: 964262
diff --git a/Kbuild b/Kbuild
index 8bf73d6..0fad9ca 100755
--- a/Kbuild
+++ b/Kbuild
@@ -1206,8 +1206,10 @@
 CDEFINES += -DWLAN_FEATURE_HOLD_RX_WAKELOCK
 endif
 
-#Enable Channel Matrix restriction for all targets
+#Enable Channel Matrix restriction for all Rome only targets
+ifneq (y,$(filter y,$(CONFIG_CNSS_EOS) $(CONFIG_ICNSS)))
 CDEFINES += -DWLAN_ENABLE_CHNL_MATRIX_RESTRICTION
+endif
 
 #features specific to mobile router use case
 ifeq ($(CONFIG_MOBILE_ROUTER), y)
diff --git a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
index e9abe6f..a7be640 100644
--- a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
+++ b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
@@ -582,6 +582,7 @@
 	tSirMsgQ msg_buf;
 	tpAddBssParams addbss_param = NULL;
 	uint32_t retcode;
+	bool is_ch_dfs = false;
 
 	/* Package WMA_ADD_BSS_REQ message parameters */
 	addbss_param = qdf_mem_malloc(sizeof(tAddBssParams));
@@ -673,8 +674,23 @@
 	/* pass on the session persona to hal */
 	addbss_param->halPersona = session->pePersona;
 
-	addbss_param->bSpectrumMgtEnabled = session->spectrumMgtEnabled ||
-		lim_isconnected_on_dfs_channel(mlm_start_req->channelNumber);
+	if (session->ch_width == CH_WIDTH_160MHZ) {
+		is_ch_dfs = true;
+	} else if (session->ch_width == CH_WIDTH_80P80MHZ) {
+		if (cds_get_channel_state(mlm_start_req->channelNumber) ==
+							CHANNEL_STATE_DFS ||
+		    cds_get_channel_state(session->ch_center_freq_seg1 -
+					    SIR_80MHZ_START_CENTER_CH_DIFF) ==
+							CHANNEL_STATE_DFS)
+			is_ch_dfs = true;
+	} else {
+		if (cds_get_channel_state(mlm_start_req->channelNumber) ==
+							CHANNEL_STATE_DFS)
+			is_ch_dfs = true;
+	}
+
+	addbss_param->bSpectrumMgtEnabled =
+				session->spectrumMgtEnabled || is_ch_dfs;
 	addbss_param->extSetStaKeyParamValid = 0;
 
 	addbss_param->dot11_mode = session->dot11mode;
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 c3f2ad9..1d2058b 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
@@ -5665,6 +5665,15 @@
 		session_entry->dfsIncludeChanWrapperIe = true;
 		wider_bw_ch_switch->newChanWidth =
 			WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ;
+		/*
+		 * This is not applicable for 20/40/80 Mhz.
+		 * Only used when we support 80+80 Mhz operation.
+		 * In case of 80+80 Mhz, this parameter indicates
+		 * center channel frequency index of 80 Mhz channel of
+		 * frequency segment 1.
+		 */
+		wider_bw_ch_switch->newCenterChanFreq1 =
+			dfs_csa_ie_req->ch_params.center_freq_seg1;
 		break;
 	default:
 		session_entry->dfsIncludeChanWrapperIe = false;
@@ -5678,14 +5687,6 @@
 	/* Fetch the center channel based on the channel width */
 	wider_bw_ch_switch->newCenterChanFreq0 =
 		dfs_csa_ie_req->ch_params.center_freq_seg0;
-	/*
-	 * This is not applicable for 20/40/80 Mhz.Only used when we support
-	 * 80+80 Mhz operation. In case of 80+80 Mhz, this parameter indicates
-	 * center channel frequency index of 80 Mhz channel of
-	 * frequency segment 1.
-	 */
-	wider_bw_ch_switch->newCenterChanFreq1 =
-		dfs_csa_ie_req->ch_params.center_freq_seg1;
 skip_vht:
 	/* Send CSA IE request from here */
 	if (sch_set_fixed_beacon_fields(mac_ctx, session_entry) !=
diff --git a/core/mac/src/pe/lim/lim_send_messages.c b/core/mac/src/pe/lim/lim_send_messages.c
index 1023060..3c844b8 100644
--- a/core/mac/src/pe/lim/lim_send_messages.c
+++ b/core/mac/src/pe/lim/lim_send_messages.c
@@ -244,10 +244,21 @@
 	lim_log(pMac, LOG2, FL("nss value: %d"), pChnlParams->nss);
 
 	/*Set DFS flag for DFS channel */
-	if (cds_get_channel_state(chnlNumber) == CHANNEL_STATE_DFS)
+	if (ch_width == CH_WIDTH_160MHZ) {
 		pChnlParams->isDfsChannel = true;
-	else
+	} else if (ch_width == CH_WIDTH_80P80MHZ) {
 		pChnlParams->isDfsChannel = false;
+		if (cds_get_channel_state(chnlNumber) == CHANNEL_STATE_DFS ||
+		    cds_get_channel_state(pChnlParams->ch_center_freq_seg1 -
+				SIR_80MHZ_START_CENTER_CH_DIFF) ==
+							CHANNEL_STATE_DFS)
+			pChnlParams->isDfsChannel = true;
+	} else {
+		if (cds_get_channel_state(chnlNumber) == CHANNEL_STATE_DFS)
+			pChnlParams->isDfsChannel = true;
+		else
+			pChnlParams->isDfsChannel = false;
+	}
 
 	pChnlParams->restart_on_chan_switch = is_restart;
 
diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
index fa2dcd3..9f9a145 100644
--- a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
+++ b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
@@ -2397,6 +2397,9 @@
 	tSirMsgQ mmhMsg;
 	tpSwitchChannelParams pSmeSwithChnlParams;
 	uint8_t channelId;
+	bool is_ch_dfs = false;
+	enum ch_width ch_width;
+	uint8_t ch_center_freq_seg1;
 
 	pSmeSwithChnlParams = (tSwitchChannelParams *)
 			      qdf_mem_malloc(sizeof(tSwitchChannelParams));
@@ -2413,6 +2416,8 @@
 		     sizeof(tSwitchChannelParams));
 
 	channelId = pSmeSwithChnlParams->channelNumber;
+	ch_width = pSmeSwithChnlParams->ch_width;
+	ch_center_freq_seg1 = pSmeSwithChnlParams->ch_center_freq_seg1;
 
 	/*
 	 * Pass the sme sessionID to SME instead
@@ -2432,7 +2437,20 @@
 	 * upper layers to start the beacon transmission .
 	 */
 
-	if (CHANNEL_STATE_DFS != cds_get_channel_state(channelId)) {
+	if (ch_width == CH_WIDTH_160MHZ) {
+		is_ch_dfs = true;
+	} else if (ch_width == CH_WIDTH_80P80MHZ) {
+		if (cds_get_channel_state(channelId) == CHANNEL_STATE_DFS ||
+		    cds_get_channel_state(ch_center_freq_seg1 -
+					SIR_80MHZ_START_CENTER_CH_DIFF) ==
+							CHANNEL_STATE_DFS)
+			is_ch_dfs = true;
+	} else {
+		if (cds_get_channel_state(channelId) == CHANNEL_STATE_DFS)
+			is_ch_dfs = true;
+	}
+
+	if (!is_ch_dfs) {
 		if (channelId == psessionEntry->currentOperChannel) {
 			lim_apply_configuration(pMac, psessionEntry);
 			lim_send_beacon_ind(pMac, psessionEntry);
diff --git a/core/sap/src/sap_api_link_cntl.c b/core/sap/src/sap_api_link_cntl.c
index 81713b0..78b71b4 100644
--- a/core/sap/src/sap_api_link_cntl.c
+++ b/core/sap/src/sap_api_link_cntl.c
@@ -430,6 +430,7 @@
 {
 	tWLAN_SAPEvent sap_event;
 	QDF_STATUS qdf_status;
+	bool is_ch_dfs = false;
 	/*
 	 * Channel change is successful. If the new channel is a DFS channel,
 	 * then we will to perform channel availability check for 60 seconds
@@ -442,8 +443,23 @@
 	if (eSAP_DISCONNECTING != sap_ctx->sapsMachine)
 		return;
 
+	if (sap_ctx->ch_params.ch_width == CH_WIDTH_160MHZ) {
+		is_ch_dfs = true;
+	} else if (sap_ctx->ch_params.ch_width == CH_WIDTH_80P80MHZ) {
+		if (cds_get_channel_state(sap_ctx->channel) ==
+						CHANNEL_STATE_DFS ||
+		    cds_get_channel_state(sap_ctx->ch_params.center_freq_seg1 -
+					  SIR_80MHZ_START_CENTER_CH_DIFF) ==
+							CHANNEL_STATE_DFS)
+			is_ch_dfs = true;
+	} else {
+		if (cds_get_channel_state(sap_ctx->channel) ==
+						CHANNEL_STATE_DFS)
+			is_ch_dfs = true;
+	}
+
 	/* check if currently selected channel is a DFS channel */
-	if (CHANNEL_STATE_DFS == cds_get_channel_state(sap_ctx->channel)) {
+	if (is_ch_dfs) {
 		if ((false == mac_ctx->sap.SapDfsInfo.ignore_cac)
 		    && (eSAP_DFS_DO_NOT_SKIP_CAC ==
 			mac_ctx->sap.SapDfsInfo.cac_state)) {
diff --git a/core/sap/src/sap_fsm.c b/core/sap/src/sap_fsm.c
index 42fa493..44d8a8c 100644
--- a/core/sap/src/sap_fsm.c
+++ b/core/sap/src/sap_fsm.c
@@ -1078,6 +1078,8 @@
 
 	switch (ch_width) {
 	/* VHT80 */
+	case CH_WIDTH_160MHZ:
+	case CH_WIDTH_80P80MHZ:
 	case CH_WIDTH_80MHZ:
 		for (i = 0; i < MAX_80MHZ_BANDS; i++) {
 			start_channel = bitmap->chanBondingSet[i].startChannel;
@@ -1499,28 +1501,28 @@
 		 * channel list from bitmap
 		 */
 		if (ch_width != CH_WIDTH_20MHZ) {
+			bool flag = false;
+			uint8_t count = 0, new_160_startchannel = 0;
+			uint8_t index = 0, sec_seg_ch = 0;
+			uint8_t primary_seg_start_ch = 0;
 			available_ch_cnt =
 				sap_populate_available_channels(&channelBitmap,
 							ch_width,
 							availableChannels);
+
 			/*
-			 * if no valid channel bonding found,
+			 * If no valid channel bonding found,
 			 * fallback to lower bandwidth
 			 */
 			if (available_ch_cnt == 0) {
-				if (ch_width == CH_WIDTH_80MHZ) {
+				if ((ch_width == CH_WIDTH_160MHZ) ||
+					(ch_width == CH_WIDTH_80P80MHZ) ||
+					(ch_width == CH_WIDTH_80MHZ)) {
 					QDF_TRACE(QDF_MODULE_ID_SAP,
 						  QDF_TRACE_LEVEL_WARN,
-						  FL
-						  ("sapdfs:No 80MHz cb found, falling to 40MHz"));
-					QDF_TRACE(QDF_MODULE_ID_SAP,
-						  QDF_TRACE_LEVEL_WARN,
-						  FL
-						  ("sapdfs:Changing chanWidth from [%d] to [%d]"),
-						  ch_width,
-						  CH_WIDTH_40MHZ);
+						  FL("sapdfs:Changing chanWidth from [%d] to 40Mhz"),
+						  ch_width);
 					ch_width = CH_WIDTH_40MHZ;
-					/* continue to start of do loop */
 					continue;
 				} else if (ch_width == CH_WIDTH_40MHZ) {
 					QDF_TRACE(QDF_MODULE_ID_SAP,
@@ -1538,47 +1540,167 @@
 					continue;
 				}
 			}
-		}
 
-		/*
-		 * by now, available channels list will be populated or
-		 * no channels are avaialbe
-		 */
-		if (available_ch_cnt) {
-			for (i = 0; i < available_ch_cnt; i++) {
-				if (CDS_IS_DFS_CH(availableChannels[i])) {
-					avail_dfs_chan_list[
-						avail_dfs_chan_count++] =
-							availableChannels[i];
-				} else {
-					avail_non_dfs_chan_list[
-						avail_non_dfs_chan_count++] =
-							availableChannels[i];
-				}
+			/*
+			 * Number of channel count should be more than 8 to
+			 * switch new channel in 160Mhz band
+			 */
+			if (((ch_width == CH_WIDTH_160MHZ) ||
+				(ch_width == CH_WIDTH_80P80MHZ)) &&
+				(available_ch_cnt < SIR_DFS_MAX_20M_SUB_CH)) {
+				QDF_TRACE(QDF_MODULE_ID_SAP,
+					QDF_TRACE_LEVEL_WARN,
+					FL("sapdfs:Changing chanWidth from [%d] to [%d]"),
+					ch_width, CH_WIDTH_80MHZ);
+				ch_width = CH_WIDTH_80MHZ;
+				continue;
 			}
-		} else {
-			QDF_TRACE(QDF_MODULE_ID_SAP,
+			if (ch_width == CH_WIDTH_160MHZ) {
+				/*
+				 * NA supports only 2 blocks for 160Mhz
+				 * bandwidth i.e 36-64 & 100-128 and
+				 * all the channels in these blocks are
+				 * continuous and seperated by 4Mhz.
+				 */
+				for (i = 1; ((i < available_ch_cnt)); i++) {
+					if ((availableChannels[i] -
+						availableChannels[i-1]) == 4)
+						count++;
+					else
+						count = 0;
+					if (count ==
+						SIR_DFS_MAX_20M_SUB_CH - 1) {
+						flag = true;
+						new_160_startchannel =
+							availableChannels[i-7];
+						break;
+					}
+				}
+			} else if (ch_width == CH_WIDTH_80P80MHZ) {
+					flag = true;
+			}
+			if ((flag == false) && (ch_width > CH_WIDTH_80MHZ)) {
+				ch_width = CH_WIDTH_80MHZ;
+				continue;
+			}
+
+			if (ch_width == CH_WIDTH_160MHZ) {
+				cds_rand_get_bytes(0, (uint8_t *)&random_byte,
+						   1);
+				random_byte = (random_byte +
+						qdf_mc_timer_get_system_ticks())
+						% SIR_DFS_MAX_20M_SUB_CH;
+				pMac->sap.SapDfsInfo.new_chanWidth = ch_width;
+				target_channel = new_160_startchannel +
+							(random_byte * 4);
+				QDF_TRACE(QDF_MODULE_ID_SAP,
 					QDF_TRACE_LEVEL_INFO_LOW,
-					FL("No target channel found"));
+					FL("sapdfs: New Channel width = %d"),
+					pMac->sap.SapDfsInfo.new_chanWidth);
+				QDF_TRACE(QDF_MODULE_ID_SAP,
+					QDF_TRACE_LEVEL_INFO_LOW,
+					FL("sapdfs: target_channel = %d"),
+					target_channel);
+
+				qdf_mem_free(tmp_ch_lst);
+				return target_channel;
+			} else if (ch_width == CH_WIDTH_80P80MHZ) {
+				cds_rand_get_bytes(0,
+						(uint8_t *)&random_byte, 1);
+				index = (random_byte +
+					qdf_mc_timer_get_system_ticks()) %
+					available_ch_cnt;
+				target_channel = availableChannels[index];
+				index -= (index % 4);
+				primary_seg_start_ch = availableChannels[index];
+
+				/* reset channels associate with primary 80Mhz */
+				for (i = 0; i < 4; i++)
+					availableChannels[i + index] = 0;
+				/*
+				 * select and calculate center frequency for
+				 * secondary segement
+				 */
+				for (i = 0; i < available_ch_cnt / 4; i++) {
+					if (availableChannels[i * 4] &&
+					    (abs(primary_seg_start_ch -
+						 availableChannels[i * 4]) >
+						(SIR_DFS_MAX_20M_SUB_CH * 2))) {
+
+						sec_seg_ch =
+						  availableChannels[i * 4] +
+						SIR_80MHZ_START_CENTER_CH_DIFF;
+
+						break;
+					}
+				}
+				if (!sec_seg_ch &&
+					(available_ch_cnt ==
+						SIR_DFS_MAX_20M_SUB_CH))
+					ch_width = CH_WIDTH_160MHZ;
+				else if (!sec_seg_ch)
+					ch_width = CH_WIDTH_80MHZ;
+
+				pMac->sap.SapDfsInfo.new_ch_params.center_freq_seg1
+						= sec_seg_ch;
+				pMac->sap.SapDfsInfo.new_chanWidth = ch_width;
+
+				QDF_TRACE(QDF_MODULE_ID_SAP,
+					QDF_TRACE_LEVEL_INFO_LOW,
+					FL("sapdfs: New Channel width = %d"),
+					pMac->sap.SapDfsInfo.new_chanWidth);
+				QDF_TRACE(QDF_MODULE_ID_SAP,
+					QDF_TRACE_LEVEL_INFO_LOW,
+					FL("sapdfs: New Center Freq Seg1 = %d"),
+					sec_seg_ch);
+				QDF_TRACE(QDF_MODULE_ID_SAP,
+					QDF_TRACE_LEVEL_INFO_LOW,
+					FL("sapdfs: target_channel = %d"),
+					target_channel);
+
+				qdf_mem_free(tmp_ch_lst);
+
+				return target_channel;
+			}
+			/*
+			 * by now, available channels list will be populated or
+			 * no channels are avaialbe
+			 */
+			if (available_ch_cnt) {
+				for (i = 0; i < available_ch_cnt; i++) {
+					if (CDS_IS_DFS_CH(availableChannels[i])) {
+						avail_dfs_chan_list[
+							avail_dfs_chan_count++] =
+								availableChannels[i];
+					} else {
+						avail_non_dfs_chan_list[
+							avail_non_dfs_chan_count++] =
+								availableChannels[i];
+					}
+				}
+			} else {
+				QDF_TRACE(QDF_MODULE_ID_SAP,
+						QDF_TRACE_LEVEL_INFO_LOW,
+						FL("No target channel found"));
+			}
+
+			cds_rand_get_bytes(0, (uint8_t *)&random_byte, 1);
+
+			/* Give preference to non-DFS channel */
+			if (!pMac->f_prefer_non_dfs_on_radar) {
+				i = (random_byte + qdf_mc_timer_get_system_ticks()) %
+					available_ch_cnt;
+				target_channel = availableChannels[i];
+			} else if (avail_non_dfs_chan_count) {
+				i = (random_byte + qdf_mc_timer_get_system_ticks()) %
+					avail_non_dfs_chan_count;
+				target_channel = avail_non_dfs_chan_list[i];
+			} else {
+				i = (random_byte + qdf_mc_timer_get_system_ticks()) %
+					avail_dfs_chan_count;
+				target_channel = avail_dfs_chan_list[i];
+			}
 		}
-
-		cds_rand_get_bytes(0, (uint8_t *)&random_byte, 1);
-
-		/* Give preference to non-DFS channel */
-		if (!pMac->f_prefer_non_dfs_on_radar) {
-			i = (random_byte + qdf_mc_timer_get_system_ticks()) %
-				available_ch_cnt;
-			target_channel = availableChannels[i];
-		} else if (avail_non_dfs_chan_count) {
-			i = (random_byte + qdf_mc_timer_get_system_ticks()) %
-				avail_non_dfs_chan_count;
-			target_channel = avail_non_dfs_chan_list[i];
-		} else {
-			i = (random_byte + qdf_mc_timer_get_system_ticks()) %
-				avail_dfs_chan_count;
-			target_channel = avail_dfs_chan_list[i];
-		}
-
 		pMac->sap.SapDfsInfo.new_chanWidth = ch_width;
 		QDF_TRACE(QDF_MODULE_ID_SAP,
 				QDF_TRACE_LEVEL_INFO_LOW,
diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c
index 9961c66..07fd127 100644
--- a/core/sap/src/sap_module.c
+++ b/core/sap/src/sap_module.c
@@ -2279,7 +2279,7 @@
 	void *hHal = NULL;
 	tpAniSirGlobal mac_ctx = NULL;
 	eCsrPhyMode phy_mode;
-	struct ch_params_s ch_params;
+	struct ch_params_s *ch_params;
 	sapContext = (ptSapContext) pSapCtx;
 
 	if (NULL == sapContext) {
@@ -2302,16 +2302,16 @@
 	 * because we've implemented channel width fallback mechanism for DFS
 	 * which will result in channel width changing dynamically.
 	 */
-	ch_params.ch_width = mac_ctx->sap.SapDfsInfo.new_chanWidth;
-	sme_set_ch_params(hHal, phy_mode, target_channel, 0, &ch_params);
-	sapContext->ch_params.ch_width = ch_params.ch_width;
+	ch_params = &mac_ctx->sap.SapDfsInfo.new_ch_params;
+	sme_set_ch_params(hHal, phy_mode, target_channel, 0, ch_params);
+	sapContext->ch_params.ch_width = ch_params->ch_width;
 	/* Update the channel as this will be used to
 	 * send event to supplicant
 	 */
 	sapContext->channel = target_channel;
-	sapContext->csr_roamProfile.ch_params.ch_width = ch_params.ch_width;
+	sapContext->csr_roamProfile.ch_params.ch_width = ch_params->ch_width;
 	qdf_ret_status = sme_roam_channel_change_req(hHal, sapContext->bssid,
-				&ch_params, &sapContext->csr_roamProfile);
+				ch_params, &sapContext->csr_roamProfile);
 
 	if (qdf_ret_status == QDF_STATUS_SUCCESS) {
 		sap_signal_hdd_event(sapContext, NULL,
@@ -2430,6 +2430,13 @@
 	}
 	pMac = PMAC_STRUCT(hHal);
 
+	pMac->sap.SapDfsInfo.new_ch_params.ch_width =
+				pMac->sap.SapDfsInfo.new_chanWidth;
+
+	sme_set_ch_params(hHal, sapContext->csr_roamProfile.phyMode,
+				pMac->sap.SapDfsInfo.target_channel, 0,
+				&pMac->sap.SapDfsInfo.new_ch_params);
+
 	qdf_ret_status = sme_roam_csa_ie_request(hHal,
 				sapContext->bssid,
 				pMac->sap.SapDfsInfo.target_channel,