Browse Source

qcacld-3.0: Fix CSA process wide BW IE bandwidth issue

During channel switch for station mode, firmware reports CSA
offload event to host driver, if the beacon IE includes wide
band width IE, driver will process it and then set phy mode
into firmware. Because function lim_process_csa_wbw_ie try to
verify the segments and channel bandwidth in wrong way, it will
lead to device use bandwidth which is mismatched with AP after
channel switch. So data transaction gets failure.
Fix this issue to verify channel bandwidth by correct algorithm.

Change-Id: Ie26c3a887418dc61c0e8de041a9094aa82215098
CRs-Fixed: 2782049
Zhaoyang Liu 4 years ago
parent
commit
1d5b3d03c8
1 changed files with 111 additions and 74 deletions
  1. 111 74
      core/mac/src/pe/lim/lim_send_sme_rsp_messages.c

+ 111 - 74
core/mac/src/pe/lim/lim_send_sme_rsp_messages.c

@@ -1425,94 +1425,132 @@ static QDF_STATUS lim_process_csa_wbw_ie(struct mac_context *mac_ctx,
 {
 	struct ch_params ch_params = {0};
 	uint8_t ap_new_ch_width;
-	bool new_ch_width_dfn = false;
 	uint8_t center_freq_diff;
 	uint32_t fw_vht_ch_wd = wma_get_vht_ch_width() + 1;
+	uint32_t cent_freq1, cent_freq2;
+	uint32_t csa_cent_freq, csa_cent_freq1 = 0, csa_cent_freq2 = 0;
 
 	ap_new_ch_width = csa_params->new_ch_width + 1;
 
-	if ((ap_new_ch_width != CH_WIDTH_80MHZ) &&
-			(ap_new_ch_width != CH_WIDTH_160MHZ) &&
-			(ap_new_ch_width != CH_WIDTH_80P80MHZ)) {
-		pe_err("CSA wide BW IE has wrong ch_width %d",
-				csa_params->new_ch_width);
-		return QDF_STATUS_E_INVAL;
-	}
-
 	if (!csa_params->new_ch_freq_seg1 && !csa_params->new_ch_freq_seg2) {
 		pe_err("CSA wide BW IE has invalid center freq");
 		return QDF_STATUS_E_INVAL;
 	}
-	if ((ap_new_ch_width == CH_WIDTH_80MHZ) &&
-			csa_params->new_ch_freq_seg2) {
-		new_ch_width_dfn = true;
-		if (csa_params->new_ch_freq_seg2 >
-				csa_params->new_ch_freq_seg1)
-			center_freq_diff = csa_params->new_ch_freq_seg2 -
-				csa_params->new_ch_freq_seg1;
-		else
-			center_freq_diff = csa_params->new_ch_freq_seg1 -
-				csa_params->new_ch_freq_seg2;
-		if (center_freq_diff == CENTER_FREQ_DIFF_160MHz)
-			ap_new_ch_width = CH_WIDTH_160MHZ;
-		else if (center_freq_diff > CENTER_FREQ_DIFF_80P80MHz)
-			ap_new_ch_width = CH_WIDTH_80P80MHZ;
-		else
-			ap_new_ch_width = CH_WIDTH_80MHZ;
+
+	csa_cent_freq = csa_params->csa_chan_freq;
+	if (wlan_reg_is_6ghz_op_class(mac_ctx->pdev,
+				      csa_params->new_op_class)) {
+		cent_freq1 = wlan_reg_chan_opclass_to_freq(
+					csa_params->new_ch_freq_seg1,
+					csa_params->new_op_class, false);
+		cent_freq2 = wlan_reg_chan_opclass_to_freq(
+					csa_params->new_ch_freq_seg2,
+					csa_params->new_op_class, false);
+	} else {
+		cent_freq1 = wlan_reg_legacy_chan_to_freq(mac_ctx->pdev,
+					csa_params->new_ch_freq_seg1);
+		cent_freq2 = wlan_reg_legacy_chan_to_freq(mac_ctx->pdev,
+					csa_params->new_ch_freq_seg2);
 	}
-	session_entry->gLimChannelSwitch.state =
-		eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY;
-	if ((ap_new_ch_width == CH_WIDTH_160MHZ) &&
-			!new_ch_width_dfn) {
-		if (abs(csa_params->new_ch_freq_seg1 - csa_params->channel) !=
-				CH_TO_CNTR_FREQ_DIFF_160MHz) {
-			pe_err("CSA wide BW IE has invalid center freq");
-			return QDF_STATUS_E_INVAL;
+
+	switch (ap_new_ch_width) {
+	case CH_WIDTH_80MHZ:
+		csa_cent_freq1 = cent_freq1;
+		if (csa_params->new_ch_freq_seg2) {
+			center_freq_diff = abs(csa_params->new_ch_freq_seg2 -
+					       csa_params->new_ch_freq_seg1);
+			if (center_freq_diff == CENTER_FREQ_DIFF_160MHz) {
+				ap_new_ch_width = CH_WIDTH_160MHZ;
+				csa_cent_freq1 = cent_freq2;
+				csa_params->new_ch_freq_seg1 =
+						csa_params->new_ch_freq_seg2;
+				csa_params->new_ch_freq_seg2 = 0;
+			} else if (center_freq_diff > CENTER_FREQ_DIFF_160MHz) {
+				ap_new_ch_width = CH_WIDTH_80P80MHZ;
+				csa_cent_freq2 = cent_freq2;
+			}
 		}
+		break;
+	case CH_WIDTH_80P80MHZ:
+		csa_cent_freq1 = cent_freq1;
+		csa_cent_freq2 = cent_freq2;
+		break;
+	case CH_WIDTH_160MHZ:
+		csa_cent_freq1 = cent_freq1;
+		break;
+	default:
+		pe_err("CSA wide BW IE has wrong ch_width %d", ap_new_ch_width);
+		return QDF_STATUS_E_INVAL;
+	}
 
-		if (ap_new_ch_width > fw_vht_ch_wd) {
-			pe_debug("New BW is not supported, setting BW to %d",
-				 fw_vht_ch_wd);
-			ap_new_ch_width = fw_vht_ch_wd;
+	/* Verify whether the bandwidth and channel segments are valid. */
+	switch (ap_new_ch_width) {
+	case CH_WIDTH_80MHZ:
+		if (abs(csa_cent_freq1 - csa_cent_freq) != 10 &&
+		    abs(csa_cent_freq1 - csa_cent_freq) != 30) {
+			pe_err("CSA WBW 80MHz has invalid seg0 freq %d",
+			       csa_cent_freq1);
+			return QDF_STATUS_E_INVAL;
 		}
-		ch_params.ch_width = ap_new_ch_width ;
-		wlan_reg_set_channel_params(mac_ctx->pdev,
-					    csa_params->channel, 0, &ch_params);
-		ap_new_ch_width = ch_params.ch_width;
-		csa_params->new_ch_freq_seg1 = ch_params.center_freq_seg0;
-		csa_params->new_ch_freq_seg2 = ch_params.center_freq_seg1;
-	} else if (!new_ch_width_dfn) {
-		if (ap_new_ch_width > fw_vht_ch_wd) {
-			pe_debug("New BW is not supported, setting BW to %d",
-				 fw_vht_ch_wd);
-			ap_new_ch_width = fw_vht_ch_wd;
+		if (csa_cent_freq2) {
+			pe_err("CSA WBW 80MHz has invalid seg1 freq %d",
+			       csa_cent_freq2);
+			return QDF_STATUS_E_INVAL;
 		}
-		if (abs(csa_params->new_ch_freq_seg1 - csa_params->channel) !=
-				CH_TO_CNTR_FREQ_DIFF_80MHz) {
-			pe_err("CSA wide BW IE has invalid center freq");
+		break;
+	case CH_WIDTH_80P80MHZ:
+		if (abs(csa_cent_freq1 - csa_cent_freq) != 10 &&
+		    abs(csa_cent_freq1 - csa_cent_freq) != 30) {
+			pe_err("CSA WBW 80MHz has invalid seg0 freq %d",
+			       csa_cent_freq1);
 			return QDF_STATUS_E_INVAL;
 		}
-		csa_params->new_ch_freq_seg2 = 0;
-	}
-	if (new_ch_width_dfn) {
-		if (abs(csa_params->new_ch_freq_seg1 - csa_params->channel) !=
-				CH_TO_CNTR_FREQ_DIFF_80MHz) {
-			pe_err("CSA wide BW IE has invalid center freq");
+		if (!csa_cent_freq2) {
+			pe_err("CSA WBW 80MHz has invalid seg1 freq %d",
+			       csa_cent_freq2);
 			return QDF_STATUS_E_INVAL;
 		}
-		if (ap_new_ch_width > fw_vht_ch_wd) {
-			pe_debug("New width is not supported, setting BW to %d",
-				 fw_vht_ch_wd);
-			ap_new_ch_width = fw_vht_ch_wd;
+		/* adjacent is not allowed -- that's a 160 MHz channel */
+		if (abs(csa_cent_freq1 - csa_cent_freq2) == 80) {
+			pe_err("CSA WBW wrong bandwidth");
+			return QDF_STATUS_E_INVAL;
 		}
-		if ((ap_new_ch_width == CH_WIDTH_160MHZ) &&
-		    (abs(csa_params->new_ch_freq_seg1 - csa_params->channel) !=
-				 CH_TO_CNTR_FREQ_DIFF_160MHz)) {
-			pe_err("wide BW IE has invalid 160M center freq");
-			csa_params->new_ch_freq_seg2 = 0;
-			ap_new_ch_width = CH_WIDTH_80MHZ;
+		break;
+	case CH_WIDTH_160MHZ:
+		if (abs(csa_cent_freq1 - csa_cent_freq) != 70 &&
+		    abs(csa_cent_freq1 - csa_cent_freq) != 50 &&
+		    abs(csa_cent_freq1 - csa_cent_freq) != 30 &&
+		    abs(csa_cent_freq1 - csa_cent_freq) != 10) {
+			pr_err("CSA WBW 160MHz has invalid seg0 freq %d",
+			       csa_cent_freq1);
+			return QDF_STATUS_E_INVAL;
+		}
+		if (csa_cent_freq2) {
+			pe_err("CSA WBW 80MHz has invalid seg1 freq %d",
+			       csa_cent_freq2);
+			return QDF_STATUS_E_INVAL;
 		}
+		break;
+	default:
+		pe_err("CSA wide BW IE has wrong ch_width %d", ap_new_ch_width);
+		return QDF_STATUS_E_INVAL;
 	}
+
+	if (ap_new_ch_width > fw_vht_ch_wd) {
+		pe_debug("New BW is not supported, setting BW to %d",
+			 fw_vht_ch_wd);
+		ap_new_ch_width = fw_vht_ch_wd;
+		ch_params.ch_width = ap_new_ch_width;
+		wlan_reg_set_channel_params(mac_ctx->pdev,
+					    csa_params->channel, 0, &ch_params);
+		ap_new_ch_width = ch_params.ch_width;
+		csa_params->new_ch_freq_seg1 = ch_params.center_freq_seg0;
+		csa_params->new_ch_freq_seg2 = ch_params.center_freq_seg1;
+	}
+
+	session_entry->gLimChannelSwitch.state =
+		eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY;
+
 	chnl_switch_info->newChanWidth = ap_new_ch_width;
 	chnl_switch_info->newCenterChanFreq0 = csa_params->new_ch_freq_seg1;
 	chnl_switch_info->newCenterChanFreq1 = csa_params->new_ch_freq_seg2;
@@ -1658,13 +1696,12 @@ void lim_handle_csa_offload_msg(struct mac_context *mac_ctx,
 			lim_ch_switch->sec_ch_offset =
 				PHY_SINGLE_CHANNEL_CENTERED;
 			if (chnl_switch_info->newChanWidth) {
-				if (csa_params->channel <
-				  csa_params->new_ch_freq_seg1)
-					lim_ch_switch->sec_ch_offset =
-						PHY_DOUBLE_CHANNEL_LOW_PRIMARY;
-				else
-					lim_ch_switch->sec_ch_offset =
-						PHY_DOUBLE_CHANNEL_HIGH_PRIMARY;
+				ch_params.ch_width =
+					chnl_switch_info->newChanWidth;
+				wlan_reg_set_channel_params(mac_ctx->pdev,
+					csa_params->channel, 0, &ch_params);
+				lim_ch_switch->sec_ch_offset =
+					ch_params.sec_ch_offset;
 				session_entry->htSupportedChannelWidthSet =
 									true;
 			}