فهرست منبع

Merge "qcacmn: Don't allow power mode VLP for indoor AP"

Linux Build Service Account 3 سال پیش
والد
کامیت
94d3a26340

+ 3 - 0
dp/inc/cdp_txrx_hist_struct.h

@@ -62,11 +62,14 @@ enum cdp_hist_bucket_index {
  * @CDP_HIST_TYPE_SW_ENQEUE_DELAY: From stack to HW enqueue delay
  * @CDP_HIST_TYPE_HW_COMP_DELAY: From HW enqueue to completion delay
  * @CDP_HIST_TYPE_REAP_STACK: Rx HW reap to stack deliver delay
+ * @CDP_HIST_TYPE_HW_TX_COMP_DELAY: Tx completion delay based on the timestamp
+ *                                  provided by HW
  */
 enum cdp_hist_types {
 	CDP_HIST_TYPE_SW_ENQEUE_DELAY,
 	CDP_HIST_TYPE_HW_COMP_DELAY,
 	CDP_HIST_TYPE_REAP_STACK,
+	CDP_HIST_TYPE_HW_TX_COMP_DELAY,
 	CDP_HIST_TYPE_MAX,
 };
 

+ 39 - 0
dp/wifi3.0/dp_hist.c

@@ -79,6 +79,41 @@ static uint16_t dp_hist_fw2hw_dbucket[CDP_HIST_BUCKET_MAX] = {
 static uint16_t dp_hist_reap2stack_bucket[CDP_HIST_BUCKET_MAX] = {
 	0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60};
 
+/*
+ * dp_hist_hw_tx_comp_dbucket: Tx HW Completion Delay bucket in us
+ * @index_0 = 0_250 us
+ * @index_1 = 250_500 us
+ * @index_2 = 500_750 us
+ * @index_3 = 750_1000 us
+ * @index_4 = 1000_1500 us
+ * @index_5 = 1500_2000 us
+ * @index_6 = 2000_2500 us
+ * @index_7 = 2500_5000 us
+ * @index_8 = 5000_6000 us
+ * @index_9 = 6000_7000 us
+ * @index_10 = 7000_8000 us
+ * @index_11 = 8000_9000 us
+ * @index_12 = 9000+ us
+ */
+static uint16_t dp_hist_hw_tx_comp_dbucket[CDP_HIST_BUCKET_MAX] = {
+	0, 250, 500, 750, 1000, 1500, 2000, 2500, 5000, 6000, 7000, 8000, 9000};
+
+static const char *dp_hist_hw_tx_comp_dbucket_str[CDP_HIST_BUCKET_MAX + 1] = {
+	"0 to 250 us", "250 to 500 us",
+	"500 to 750 us", "750 to 1000 us",
+	"1000 to 1500 us", "1500 to 2000 us",
+	"2000 to 2500 us", "2500 to 5000 us",
+	"5000 to 6000 us", "6000 to 7000 ms",
+	"7000 to 8000 us", "8000 to 9000 us", "9000+ us"
+};
+
+const char *dp_hist_tx_hw_delay_str(uint8_t index)
+{
+	if (index > CDP_HIST_BUCKET_MAX)
+		return "Invalid index";
+	return dp_hist_hw_tx_comp_dbucket_str[index];
+}
+
 /*
  * dp_hist_find_bucket_idx: Find the bucket index
  * @bucket_array: Bucket array
@@ -129,6 +164,10 @@ static void dp_hist_fill_buckets(struct cdp_hist_bucket *hist_bucket, int value)
 		idx =  dp_hist_find_bucket_idx(
 				&dp_hist_reap2stack_bucket[0], value);
 		break;
+	case CDP_HIST_TYPE_HW_TX_COMP_DELAY:
+		idx =  dp_hist_find_bucket_idx(
+				&dp_hist_hw_tx_comp_dbucket[0], value);
+		break;
 	default:
 		break;
 	}

+ 2 - 0
dp/wifi3.0/dp_hist.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -40,4 +41,5 @@ void dp_accumulate_hist_stats(struct cdp_hist_stats *src_hist_stats,
 			      struct cdp_hist_stats *dst_hist_stats);
 void dp_copy_hist_stats(struct cdp_hist_stats *src_hist_stats,
 			struct cdp_hist_stats *dst_hist_stats);
+const char *dp_hist_tx_hw_delay_str(uint8_t index);
 #endif /* __DP_HIST_H_ */

+ 22 - 0
dp/wifi3.0/dp_htt.c

@@ -2467,10 +2467,27 @@ static void dp_sawf_msduq_map(struct htt_soc *soc, uint32_t *msg_word,
 {
 	dp_htt_sawf_msduq_map(soc, msg_word, htt_t2h_msg);
 }
+
+/*
+ * dp_sawf_mpdu_stats_handler() - HTT message handler for MPDU stats
+ * @soc: soc handle.
+ * @htt_t2h_msg: HTT message nbuf
+ *
+ * @return: void
+ */
+static void dp_sawf_mpdu_stats_handler(struct htt_soc *soc,
+				       qdf_nbuf_t htt_t2h_msg)
+{
+	dp_sawf_htt_mpdu_stats_handler(soc, htt_t2h_msg);
+}
 #else
 static void dp_sawf_msduq_map(struct htt_soc *soc, uint32_t *msg_word,
 			      qdf_nbuf_t htt_t2h_msg)
 {}
+
+static void dp_sawf_mpdu_stats_handler(struct htt_soc *soc,
+				       qdf_nbuf_t htt_t2h_msg)
+{}
 #endif
 
 /*
@@ -3527,6 +3544,11 @@ static void dp_htt_t2h_msg_handler(void *context, HTC_PACKET *pkt)
 		dp_sawf_msduq_map(soc, msg_word, htt_t2h_msg);
 		break;
 	}
+	case HTT_T2H_MSG_TYPE_STREAMING_STATS_IND:
+	{
+		dp_sawf_mpdu_stats_handler(soc, htt_t2h_msg);
+		break;
+	}
 
 	default:
 		break;

+ 0 - 2
dp/wifi3.0/dp_main.c

@@ -15266,8 +15266,6 @@ static void dp_soc_cfg_init(struct dp_soc *soc)
 
 		soc->wlan_cfg_ctx->rxdma1_enable = 0;
 		soc->wlan_cfg_ctx->num_rxdma_dst_rings_per_pdev = 1;
-		/* use only MAC0 status ring */
-		soc->wlan_cfg_ctx->num_rxdma_status_rings_per_pdev = 1;
 		break;
 	case TARGET_TYPE_QCA8074:
 		wlan_cfg_set_raw_mode_war(soc->wlan_cfg_ctx, true);

+ 16 - 11
umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h

@@ -1727,6 +1727,14 @@ struct subelem_header {
 #define EHTCAP_PPET_RU_INDEX_BITMASK_IDX  4
 #define EHTCAP_PPET_RU_INDEX_BITMASK_BITS 5
 
+#define EHTOP_INFO_PRESENT_IDX             0
+#define EHTOP_INFO_PRESENT_BITS            1
+#define EHTOP_PARAM_DISABLED_SC_BITMAP_PRESENT_IDX       1
+#define EHTOP_PARAM_DISABLED_SC_BITMAP_PRESENT_BITS      1
+
+#define EHTOP_INFO_CHAN_WIDTH_IDX          0
+#define EHTOP_INFO_CHAN_WIDTH_BITS         3
+
 #define MAX_EHT_MCS_NSS_MAP_LEN 9
 
 /**
@@ -1775,12 +1783,10 @@ struct wlan_ie_ehtcaps {
  * @elem_id: EHT caps IE
  * @elem_len: EHT caps IE len
  * @elem_id_extn: EHT caps extension id
- * @width: EHT BSS Channel Width
- * @reserved1: Reserved bits
- * @ccfs: EHT Channel Centre Frequency Segment information
- * @disable_sub_chan_bitmap_present: Flag to indicate disable subchannel
- *                                   bitmap present
- * @reserved2: Reserved bits
+ * @ehtop_param: EHT Operation Parameters
+ * @control: Control field in EHT Operation Information
+ * @ccfs0: EHT Channel Centre Frequency Segment0 information
+ * @ccfs1: EHT Channel Centre Frequency Segment1 information
  * @disable_sub_chan_bitmap: Bitmap to indicate 20MHz subchannel is punctured
  *                           or not
  */
@@ -1788,11 +1794,10 @@ struct wlan_ie_ehtops {
 	uint8_t elem_id;
 	uint8_t elem_len;
 	uint8_t elem_id_extn;
-	uint8_t width:3,
-		reserved1:5;
-	uint8_t ccfs;
-	uint8_t disable_sub_chan_bitmap_present:1,
-		reserved2:7;
+	uint8_t ehtop_param;
+	uint8_t control;
+	uint8_t ccfs0;
+	uint8_t ccfs1;
 	uint8_t disable_sub_chan_bitmap[2];
 } qdf_packed;
 

+ 10 - 0
umac/dfs/core/src/dfs.h

@@ -3122,4 +3122,14 @@ dfs_restart_rcac_on_nol_expiry(struct wlan_dfs *dfs)
 	return false;
 }
 #endif
+
+/**
+ * dfs_chan_to_ch_width: Outputs the channel width in MHz of the given input
+ * dfs_channel.
+ *
+ * chan: Pointer to the input dfs_channel structure.
+ *
+ * Return: Channel width in MHz. (uint16) -EINVAL on invalid channel.
+ */
+uint16_t dfs_chan_to_ch_width(struct dfs_channel *chan);
 #endif  /* _DFS_H_ */

+ 7 - 5
umac/dfs/core/src/dfs_process_radar_found_ind.h

@@ -28,11 +28,13 @@
 #define _DFS_PROCESS_RADAR_FOUND_IND_H_
 #include "dfs_partial_offload_radar.h"
 
-#define BW_20   20
-#define BW_40   40
-#define BW_80   80
-#define BW_160 160
-#define BW_320 320
+#define BW_INVALID    0
+#define BW_10        10
+#define BW_20        20
+#define BW_40        40
+#define BW_80        80
+#define BW_160      160
+#define BW_320      320
 /**
  * dfs_false_radarfound_reset_vars () - Reset dfs radar detection related
  * variables and queues after processing radar and disabling phyerror reception.

+ 31 - 0
umac/dfs/core/src/misc/dfs.c

@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
  * Copyright (c) 2002-2006, Atheros Communications Inc.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -859,3 +860,33 @@ uint8_t dfs_get_agile_detector_id(struct wlan_dfs *dfs)
 	return dfs->dfs_agile_detector_id;
 }
 #endif
+
+/**
+ * dfs_chan_to_ch_width: Outputs the channel width in MHz of the given input
+ * dfs_channel.
+ * @chan: Pointer to the input dfs_channel structure.
+ *
+ * Return: Channel width in MHz. BW_INVALID(0MHz) on invalid channel.
+ */
+uint16_t dfs_chan_to_ch_width(struct dfs_channel *chan)
+{
+	uint16_t ch_width;
+
+	if (!chan)
+		return BW_INVALID;
+
+	if (WLAN_IS_CHAN_MODE_320(chan))
+		ch_width = BW_320;
+	else if (WLAN_IS_CHAN_MODE_160(chan))
+		ch_width = BW_160;
+	else if (WLAN_IS_CHAN_MODE_80(chan))
+		ch_width = BW_80;
+	else if (WLAN_IS_CHAN_MODE_40(chan))
+		ch_width = BW_40;
+	else if (WLAN_IS_CHAN_MODE_20(chan))
+		ch_width = BW_20;
+	else
+		ch_width = BW_INVALID;
+
+	return ch_width;
+}

+ 35 - 108
umac/dfs/core/src/misc/dfs_process_radar_found_ind.c

@@ -215,102 +215,40 @@ dfs_radar_add_channel_list_to_nol_for_freq(struct wlan_dfs *dfs,
 	return QDF_STATUS_SUCCESS;
 }
 #endif
-/**
- * dfs_radar_chan_for_80()- Find frequency offsets for 80MHz
- * @freq_offset: freq offset
- * @center_freq: center frequency
- *
- * Find frequency offsets for 80MHz
- *
- * Return: None
- */
-static void dfs_radar_chan_for_80(struct freqs_offsets *freq_offset,
-				  uint32_t center_freq)
-{
-	int i;
-
-	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
-		if (freq_offset->offset[i] < DFS_OFFSET_SECOND_LOWER)
-			freq_offset->freq[i] =
-				DFS_THIRD_LOWER_CHANNEL(center_freq);
-		else if ((freq_offset->offset[i] > DFS_OFFSET_SECOND_LOWER) &&
-			 (freq_offset->offset[i] < DFS_OFFSET_FIRST_LOWER))
-			freq_offset->freq[i] =
-				DFS_SECOND_LOWER_CHANNEL(center_freq);
-		else if ((freq_offset->offset[i] > DFS_OFFSET_FIRST_LOWER) &&
-			 (freq_offset->offset[i] < 0))
-			freq_offset->freq[i] =
-				DFS_FIRST_LOWER_CHANNEL(center_freq);
-		else if ((freq_offset->offset[i] > 0) &&
-			  (freq_offset->offset[i] < DFS_OFFSET_FIRST_UPPER))
-			freq_offset->freq[i] =
-				DFS_FIRST_UPPER_CHANNEL(center_freq);
-		else if ((freq_offset->offset[i] > DFS_OFFSET_FIRST_UPPER) &&
-			 (freq_offset->offset[i] < DFS_OFFSET_SECOND_UPPER))
-			freq_offset->freq[i] =
-				DFS_SECOND_UPPER_CHANNEL(center_freq);
-		else if (freq_offset->offset[i] > DFS_OFFSET_SECOND_UPPER)
-			freq_offset->freq[i] =
-				DFS_THIRD_UPPER_CHANNEL(center_freq);
-	}
-}
 
 /**
- * dfs_radar_chan_for_40()- Find frequency offsets for 40MHz
- * @freq_offset: freq offset
- * @center_freq: center frequency
- *
- * Find frequency offsets for 40MHz
+ * dfs_find_20mhz_subchans_from_offsets()- Find frequency offsets
+ * that aligns with 20MHz sub-channel centers.
  *
- * Return: None
- */
-static void dfs_radar_chan_for_40(struct freqs_offsets *freq_offset,
-				  uint32_t center_freq)
-{
-	int i;
-
-	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
-		if (freq_offset->offset[i] < DFS_OFFSET_FIRST_LOWER)
-			freq_offset->freq[i] =
-				DFS_SECOND_LOWER_CHANNEL(center_freq);
-		else if ((freq_offset->offset[i] > DFS_OFFSET_FIRST_LOWER) &&
-			 (freq_offset->offset[i] < 0))
-			freq_offset->freq[i] =
-				DFS_FIRST_LOWER_CHANNEL(center_freq);
-		else if ((freq_offset->offset[i] > 0) &&
-			 (freq_offset->offset[i] < DFS_OFFSET_FIRST_UPPER))
-			freq_offset->freq[i] =
-				DFS_FIRST_UPPER_CHANNEL(center_freq);
-		else if (freq_offset->offset[i] > DFS_OFFSET_FIRST_UPPER)
-			freq_offset->freq[i] =
-				DFS_SECOND_UPPER_CHANNEL(center_freq);
-	}
-}
-
-/**
- * dfs_radar_chan_for_20()- Find frequency offsets for 20MHz
  * @freq_offset: freq offset
  * @center_freq: center frequency
- *
- * Find frequency offsets for 20MHz
+ * @ch_width: Channel Width value: 20/40/80/160/320MHz.
+ * Find frequency offsets for 80MHz
  *
  * Return: None
  */
-static void dfs_radar_chan_for_20(struct freqs_offsets *freq_offset,
-				  uint32_t center_freq)
+static void
+dfs_find_20mhz_subchans_from_offsets(struct freqs_offsets *freq_offset,
+				     uint32_t center_freq,
+				     uint16_t ch_width)
 {
-	int i;
+	uint16_t first_chan20_cen = center_freq - (ch_width / 2) + BW_10;
+	uint16_t i, j;
+	uint8_t num_20mhz_subchans = ch_width / BW_20;
 
 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
-		if (freq_offset->offset[i] <= DFS_20MZ_OFFSET_LOWER)
-			freq_offset->freq[i] =
-				DFS_20MHZ_LOWER_CHANNEL(center_freq);
-		else if ((freq_offset->offset[i] > DFS_20MZ_OFFSET_LOWER) &&
-			  (freq_offset->offset[i] < DFS_20MZ_OFFSET_UPPER))
-			freq_offset->freq[i] = center_freq;
-		else if (freq_offset->offset[i] >= DFS_20MZ_OFFSET_UPPER)
-			freq_offset->freq[i] =
-				DFS_20MHZ_UPPER_CHANNEL(center_freq);
+		uint16_t radar_found_freq =
+					center_freq + freq_offset->offset[i];
+		uint16_t chan20_cen = first_chan20_cen;
+
+		for (j = 0; j < num_20mhz_subchans; j++) {
+			if ((radar_found_freq > chan20_cen - BW_10) &&
+			    (radar_found_freq < chan20_cen + BW_10)) {
+				freq_offset->freq[i] = chan20_cen;
+				break;
+			}
+			chan20_cen += BW_20;
+		}
 	}
 }
 
@@ -410,6 +348,7 @@ dfs_find_radar_affected_subchans_for_freq(struct wlan_dfs *dfs,
 	uint8_t n_cur_subchans;
 	struct dfs_channel *curchan = dfs->dfs_curchan;
 	struct freqs_offsets freq_offset;
+	uint16_t ch_width;
 
 	qdf_mem_zero(&freq_offset, sizeof(freq_offset));
 	flag = curchan->dfs_ch_flags;
@@ -425,35 +364,23 @@ dfs_find_radar_affected_subchans_for_freq(struct wlan_dfs *dfs,
 		 radar_found->freq_offset, radar_found->is_chirp,
 		 flag, freq_center);
 
-	if ((WLAN_IS_CHAN_A(curchan)) ||
-	    WLAN_IS_CHAN_MODE_20(curchan)) {
-		if (radar_found->is_chirp ||
-		    (sidx && !(abs(sidx) % DFS_BOUNDARY_SIDX))) {
-			freq_offset.offset[LEFT_CH] -= DFS_CHIRP_OFFSET;
-			freq_offset.offset[RIGHT_CH] += DFS_CHIRP_OFFSET;
-		}
-		dfs_radar_chan_for_20(&freq_offset, freq_center);
-	} else if (WLAN_IS_CHAN_MODE_40(curchan)) {
-		if (radar_found->is_chirp || !(abs(sidx) % DFS_BOUNDARY_SIDX)) {
-			freq_offset.offset[LEFT_CH] -= DFS_CHIRP_OFFSET;
-			freq_offset.offset[RIGHT_CH] += DFS_CHIRP_OFFSET;
+	if ((WLAN_IS_CHAN_A(curchan)) || WLAN_IS_CHAN_MODE_20(curchan)) {
+		freq_offset.offset[CENTER_CH] = freq_center;
+	} else {
+		ch_width = dfs_chan_to_ch_width(curchan);
+		if (ch_width == BW_INVALID) {
+			dfs_err(dfs, WLAN_DEBUG_DFS,
+				"channel flag=%d is invalid", flag);
+			return 0;
 		}
-		dfs_radar_chan_for_40(&freq_offset, freq_center);
-	} else if (WLAN_IS_CHAN_MODE_80(curchan) ||
-			WLAN_IS_CHAN_MODE_160(curchan) ||
-			WLAN_IS_CHAN_MODE_80_80(curchan) ||
-			WLAN_IS_CHAN_MODE_320(curchan)) {
+
 		if (radar_found->is_chirp || !(abs(sidx) % DFS_BOUNDARY_SIDX)) {
 			freq_offset.offset[LEFT_CH] -= DFS_CHIRP_OFFSET;
 			freq_offset.offset[RIGHT_CH] += DFS_CHIRP_OFFSET;
 		}
-		dfs_radar_chan_for_80(&freq_offset, freq_center);
-	} else {
-		dfs_err(dfs, WLAN_DEBUG_DFS,
-			"channel flag=%d is invalid", flag);
-		return 0;
+		dfs_find_20mhz_subchans_from_offsets(&freq_offset, freq_center,
+						     ch_width);
 	}
-
 	n_cur_subchans =
 	    dfs_get_bonding_channels_for_freq(dfs, curchan,
 					      radar_found->segment_id,

+ 15 - 8
umac/mlo_mgr/src/wlan_mlo_mgr_sta.c

@@ -757,9 +757,9 @@ static inline
 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg)
 {
 	return scheduler_post_message(
-			QDF_MODULE_ID_SYS,
-			QDF_MODULE_ID_SYS,
-			QDF_MODULE_ID_SYS,
+			QDF_MODULE_ID_OS_IF,
+			QDF_MODULE_ID_SCAN,
+			QDF_MODULE_ID_OS_IF,
 			msg);
 }
 #else
@@ -781,35 +781,42 @@ void mlo_handle_sta_link_connect_failure(struct wlan_objmgr_vdev *vdev,
 	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
 	struct scheduler_msg msg = {0};
 	QDF_STATUS ret;
+	struct wlan_objmgr_vdev *assoc_vdev;
 
 	if (!mlo_dev_ctx) {
 		mlo_err("ML dev ctx is NULL");
 		return;
 	}
 
-	if (vdev != mlo_get_assoc_link_vdev(mlo_dev_ctx)) {
+	assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx);
+	if (!assoc_vdev) {
+		mlo_err("Assoc Vdev is NULL");
+		return;
+	}
+
+	if (vdev != assoc_vdev) {
 		mlo_update_connected_links(vdev, 0);
 		if (rsp->reason == CM_NO_CANDIDATE_FOUND ||
 		    rsp->reason == CM_HW_MODE_FAILURE ||
 		    rsp->reason == CM_SER_FAILURE) {
 			ret = wlan_objmgr_vdev_try_get_ref(
-					vdev, WLAN_MLO_MGR_ID);
+					assoc_vdev, WLAN_MLO_MGR_ID);
 			if (QDF_IS_STATUS_ERROR(ret)) {
 				mlo_err("Failed to get ref vdev_id %d",
-					wlan_vdev_get_id(vdev));
+					wlan_vdev_get_id(assoc_vdev));
 				return;
 			}
 			/* Since these failures happen in same context. use
 			 * scheduler to avoid deadlock by deferring context
 			 */
-			msg.bodyptr = vdev;
+			msg.bodyptr = assoc_vdev;
 			msg.callback = ml_activate_disconnect_req_sched_cb;
 			msg.flush_callback =
 				ml_activate_disconnect_req_flush_cb;
 			mlo_post_disconnect_msg(&msg);
 			if (QDF_IS_STATUS_ERROR(ret)) {
 				wlan_objmgr_vdev_release_ref(
-						vdev,
+						assoc_vdev,
 						WLAN_MLO_MGR_ID);
 				return;
 			}

+ 25 - 0
umac/regulatory/core/src/reg_services_common.c

@@ -8604,6 +8604,31 @@ reg_is_freq_idx_enabled_on_given_pwr_mode(struct wlan_regulatory_pdev_priv_obj
 	return reg_is_freq_idx_enabled_on_cur_chan_list(pdev_priv_obj,
 							freq_idx);
 }
+
+static inline QDF_STATUS
+reg_get_min_max_bw_on_given_pwr_mode(struct wlan_regulatory_pdev_priv_obj
+				     *pdev_priv_obj,
+				     enum channel_enum freq_idx,
+				     enum supported_6g_pwr_types
+				     in_6g_pwr_mode,
+				     uint16_t *min_bw,
+				     uint16_t *max_bw)
+{
+	return reg_get_min_max_bw_on_cur_chan_list(pdev_priv_obj,
+						   freq_idx,
+						   min_bw, max_bw);
+}
+
+static inline enum channel_state
+reg_get_chan_state_on_given_pwr_mode(struct wlan_regulatory_pdev_priv_obj
+				     *pdev_priv_obj,
+				     enum channel_enum freq_idx,
+				     enum supported_6g_pwr_types
+				     in_6g_pwr_mode)
+{
+	return reg_get_chan_state_on_cur_chan_list(pdev_priv_obj,
+						   freq_idx);
+}
 #endif /* CONFIG_BAND_6GHZ */
 
 bool

+ 81 - 39
umac/regulatory/core/src/reg_utils.c

@@ -38,8 +38,11 @@
 #include "reg_services_common.h"
 #include "reg_build_chan_list.h"
 #include "wlan_cm_bss_score_param.h"
+#include "qdf_str.h"
 
 #define DEFAULT_WORLD_REGDMN 0x60
+#define FCC3_FCCA 0x3A
+#define FCC6_FCCA 0x14
 
 #define IS_VALID_PSOC_REG_OBJ(psoc_priv_obj) (psoc_priv_obj)
 #define IS_VALID_PDEV_REG_OBJ(pdev_priv_obj) (pdev_priv_obj)
@@ -153,6 +156,48 @@ bool reg_is_etsi_alpha2(uint8_t *alpha2)
 	return false;
 }
 
+static
+const char *reg_get_power_mode_string(uint16_t reg_dmn_pair_id)
+{
+	switch (reg_dmn_pair_id) {
+	case FCC3_FCCA:
+	case FCC6_FCCA:
+		return "NON_VLP";
+	default:
+		return "VLP";
+	}
+}
+
+static bool reg_ctry_domain_supports_vlp(uint8_t *alpha2)
+{
+	uint16_t i;
+	int no_of_countries;
+
+	reg_get_num_countries(&no_of_countries);
+	for (i = 0; i < no_of_countries; i++) {
+		if (g_all_countries[i].alpha2[0] == alpha2[0] &&
+		    g_all_countries[i].alpha2[1] == alpha2[1]) {
+			if (!qdf_str_cmp(reg_get_power_mode_string(
+			    g_all_countries[i].reg_dmn_pair_id), "NON_VLP"))
+				return false;
+			else
+				return true;
+		}
+	}
+	return true;
+}
+
+bool reg_ctry_support_vlp(uint8_t *alpha2)
+{
+	if (((alpha2[0] == 'A') && (alpha2[1] == 'E')) ||
+	    ((alpha2[0] == 'P') && (alpha2[1] == 'E')) ||
+	    ((alpha2[0] == 'U') && (alpha2[1] == 'S')) ||
+	   !reg_ctry_domain_supports_vlp(alpha2))
+		return false;
+	else
+		return true;
+}
+
 static QDF_STATUS reg_set_non_offload_country(struct wlan_objmgr_pdev *pdev,
 					      struct set_country *cc)
 {
@@ -357,49 +402,46 @@ reg_get_6g_power_type_for_ctry(struct wlan_objmgr_psoc *psoc,
 {
 	*pwr_type_6g = REG_INDOOR_AP;
 
-	if (qdf_mem_cmp(ap_ctry, sta_ctry, REG_ALPHA2_LEN)) {
-		reg_debug("Country IE:%c%c, STA country:%c%c", ap_ctry[0],
-			  ap_ctry[1], sta_ctry[0], sta_ctry[1]);
-		*ctry_code_match = false;
-
-		/*
-		 * If reg_info=0 not included, STA should operate in VLP mode.
-		 * If STA country is US, do not return if Wi-Fi safe mode
-		 * or RF test mode or relaxed connection policy is enabled,
-		 * rather STA should operate in LPI mode.
-		 * wlan_cm_get_check_6ghz_security API returns true if
-		 * neither Safe mode nor RF test mode are enabled.
-		 * wlan_cm_get_relaxed_6ghz_conn_policy API returns true if
-		 * enabled.
-		 */
-		if (ap_pwr_type != REG_INDOOR_AP) {
-			if (!wlan_reg_is_us(sta_ctry))
-				*pwr_type_6g = REG_VERY_LOW_POWER_AP;
-			if (wlan_reg_is_us(sta_ctry) &&
-			    wlan_cm_get_check_6ghz_security(psoc) &&
-			    !wlan_cm_get_relaxed_6ghz_conn_policy(psoc)) {
-				reg_err("US VLP not supported, can't connect");
-				return QDF_STATUS_E_NOSUPPORT;
-			}
-		}
+	reg_debug("Country IE:%c%c, STA country:%c%c", ap_ctry[0],
+		  ap_ctry[1], sta_ctry[0], sta_ctry[1]);
 
-		if (wlan_reg_is_etsi(sta_ctry) &&
-		    ap_pwr_type != REG_MAX_AP_TYPE) {
-			if (!(wlan_reg_is_us(ap_ctry) &&
-			      ap_pwr_type == REG_INDOOR_AP)) {
-				reg_debug("STA ctry:%c%c, doesn't match with AP ctry, switch to VLP",
-					  sta_ctry[0], sta_ctry[1]);
-				*pwr_type_6g = REG_VERY_LOW_POWER_AP;
-			}
-		}
+	if (!qdf_mem_cmp(ap_ctry, sta_ctry, REG_ALPHA2_LEN)) {
+		*ctry_code_match = true;
+		return QDF_STATUS_SUCCESS;
+	}
 
-		if (wlan_reg_is_us(ap_ctry) && ap_pwr_type == REG_INDOOR_AP) {
-			reg_debug("AP ctry:%c%c, AP power type:%d, allow STA IN LPI",
-				  ap_ctry[0], ap_ctry[1], ap_pwr_type);
+	*ctry_code_match = false;
+	/*
+	 * If reg_info=0 not included, STA should operate in VLP mode.
+	 * If STA country doesn't support VLP, do not return if Wi-Fi
+	 * safe mode or RF test mode or enable relaxed connection policy,
+	 * rather STA should operate in LPI mode.
+	 * wlan_cm_get_check_6ghz_security API returns true if
+	 * neither Safe mode nor RF test mode are enabled.
+	 * wlan_cm_get_relaxed_6ghz_conn_policy API returns true if
+	 * enabled.
+	 */
+	if (ap_pwr_type != REG_INDOOR_AP) {
+		if (wlan_reg_ctry_support_vlp(sta_ctry) &&
+		    wlan_reg_ctry_support_vlp(ap_ctry)) {
+			reg_debug("STA ctry doesn't match with AP ctry, switch to VLP");
+			*pwr_type_6g = REG_VERY_LOW_POWER_AP;
+		} else {
+			reg_debug("AP or STA doesn't support VLP");
 			*pwr_type_6g = REG_INDOOR_AP;
 		}
-	} else {
-		*ctry_code_match = true;
+
+		if (!wlan_reg_ctry_support_vlp(sta_ctry) &&
+		    wlan_cm_get_check_6ghz_security(psoc) &&
+		    !wlan_cm_get_relaxed_6ghz_conn_policy(psoc)) {
+			reg_err("VLP not supported, can't connect");
+			return QDF_STATUS_E_NOSUPPORT;
+		}
+	}
+
+	if (ap_pwr_type == REG_INDOOR_AP) {
+		reg_debug("Indoor AP, allow STA IN LPI");
+		*pwr_type_6g = REG_INDOOR_AP;
 	}
 
 	return QDF_STATUS_SUCCESS;

+ 14 - 1
umac/regulatory/core/src/reg_utils.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -215,6 +215,14 @@ bool reg_is_us_alpha2(uint8_t *alpha2);
  */
 bool reg_is_etsi_alpha2(uint8_t *alpha2);
 
+/**
+ * reg_ctry_support_vlp - Does country code supports VLP
+ * @alpha2: country code pointer
+ *
+ * Return: true or false
+ */
+bool reg_ctry_support_vlp(uint8_t *alpha2);
+
 /**
  * reg_set_country() - Set the current regulatory country
  * @pdev: pdev device for country information
@@ -371,6 +379,11 @@ static inline bool reg_is_world_alpha2(uint8_t *alpha2)
 	return false;
 }
 
+static inline bool reg_ctry_support_vlp(uint8_t *alpha2)
+{
+	return false;
+}
+
 static inline bool reg_is_us_alpha2(uint8_t *alpha2)
 {
 	return false;

+ 8 - 0
umac/regulatory/dispatcher/inc/wlan_reg_services_api.h

@@ -1117,6 +1117,14 @@ bool wlan_reg_is_us(uint8_t *country);
 bool wlan_reg_is_etsi(uint8_t *country);
 
 
+/**
+ * wlan_reg_ctry_support_vlp() - Country supports VLP or not
+ * @country: The country information
+ *
+ * Return: true or false
+ */
+bool wlan_reg_ctry_support_vlp(uint8_t *country);
+
 /**
  * wlan_reg_set_country() - Set the current regulatory country
  * @pdev: The physical dev to set current country for

+ 5 - 0
umac/regulatory/dispatcher/src/wlan_reg_services_api.c

@@ -671,6 +671,11 @@ bool wlan_reg_is_etsi(uint8_t *country)
 	return reg_is_etsi_alpha2(country);
 }
 
+bool wlan_reg_ctry_support_vlp(uint8_t *country)
+{
+	return reg_ctry_support_vlp(country);
+}
+
 void wlan_reg_register_chan_change_callback(struct wlan_objmgr_psoc *psoc,
 					    void *cbk, void *arg)
 {

+ 68 - 25
umac/scan/dispatcher/src/wlan_scan_utils_api.c

@@ -39,6 +39,8 @@
 #define NEIGHBOR_AP_LEN 1
 #define BSS_PARAMS_LEN 1
 
+static struct he_oper_6g_param *util_scan_get_he_6g_params(uint8_t *he_ops);
+
 const char*
 util_scan_get_ev_type_name(enum scan_event_type type)
 {
@@ -191,43 +193,84 @@ util_scan_get_phymode_11be(struct wlan_objmgr_pdev *pdev,
 			   uint8_t band_mask)
 {
 	struct wlan_ie_ehtops *eht_ops;
+	uint8_t width;
 
 	eht_ops = (struct wlan_ie_ehtops *)util_scan_entry_ehtop(scan_params);
 	if (!util_scan_entry_ehtcap(scan_params) || !eht_ops)
 		return phymode;
 
-	switch (eht_ops->width) {
-	case WLAN_EHT_CHWIDTH_20:
-		phymode = WLAN_PHYMODE_11BEA_EHT20;
-		break;
-	case WLAN_EHT_CHWIDTH_40:
-		phymode = WLAN_PHYMODE_11BEA_EHT40;
-		break;
-	case WLAN_EHT_CHWIDTH_80:
-		phymode = WLAN_PHYMODE_11BEA_EHT80;
-		break;
-	case WLAN_EHT_CHWIDTH_160:
-		phymode = WLAN_PHYMODE_11BEA_EHT160;
-		break;
-	case WLAN_EHT_CHWIDTH_320:
-		phymode = WLAN_PHYMODE_11BEA_EHT320;
-		break;
-	default:
-		scm_debug("Invalid eht_ops width: %d", eht_ops->width);
-		phymode = WLAN_PHYMODE_11BEA_EHT20;
-		break;
+	if (QDF_GET_BITS(eht_ops->ehtop_param,
+			 EHTOP_INFO_PRESENT_IDX, EHTOP_INFO_PRESENT_BITS)) {
+		width = QDF_GET_BITS(eht_ops->control,
+				     EHTOP_INFO_CHAN_WIDTH_IDX,
+				     EHTOP_INFO_CHAN_WIDTH_BITS);
+		switch (width) {
+		case WLAN_EHT_CHWIDTH_20:
+			phymode = WLAN_PHYMODE_11BEA_EHT20;
+			break;
+		case WLAN_EHT_CHWIDTH_40:
+			phymode = WLAN_PHYMODE_11BEA_EHT40;
+			break;
+		case WLAN_EHT_CHWIDTH_80:
+			phymode = WLAN_PHYMODE_11BEA_EHT80;
+			break;
+		case WLAN_EHT_CHWIDTH_160:
+			phymode = WLAN_PHYMODE_11BEA_EHT160;
+			break;
+		case WLAN_EHT_CHWIDTH_320:
+			phymode = WLAN_PHYMODE_11BEA_EHT320;
+			break;
+		default:
+			scm_debug("Invalid eht_ops width: %d", width);
+			phymode = WLAN_PHYMODE_11BEA_EHT20;
+			break;
+		}
+	} else {
+		switch (phymode) {
+		case WLAN_PHYMODE_11AXA_HE20:
+			phymode = WLAN_PHYMODE_11BEA_EHT20;
+			break;
+		case WLAN_PHYMODE_11AXG_HE20:
+			phymode = WLAN_PHYMODE_11BEG_EHT20;
+			break;
+		case WLAN_PHYMODE_11AXA_HE40:
+			phymode = WLAN_PHYMODE_11BEA_EHT40;
+			break;
+		case WLAN_PHYMODE_11AXG_HE40:
+			phymode = WLAN_PHYMODE_11BEG_EHT40;
+			break;
+		case WLAN_PHYMODE_11AXA_HE80:
+			phymode = WLAN_PHYMODE_11BEA_EHT80;
+			break;
+		case WLAN_PHYMODE_11AXA_HE160:
+			phymode = WLAN_PHYMODE_11BEA_EHT160;
+			break;
+		default:
+			break;
+		}
 	}
 
-	scan_params->channel.cfreq1 =
-		wlan_reg_chan_band_to_freq(pdev,
-					   eht_ops->ccfs,
-					   band_mask);
+	if (QDF_GET_BITS(eht_ops->ehtop_param,
+			 EHTOP_INFO_PRESENT_IDX, EHTOP_INFO_PRESENT_BITS)) {
+		scan_params->channel.cfreq0 =
+			wlan_reg_chan_band_to_freq(pdev,
+						   eht_ops->ccfs0,
+						   band_mask);
+		scan_params->channel.cfreq1 =
+			wlan_reg_chan_band_to_freq(pdev,
+						   eht_ops->ccfs1,
+						   band_mask);
+	}
 
-	if (eht_ops->disable_sub_chan_bitmap_present) {
+	if (QDF_GET_BITS(eht_ops->ehtop_param,
+			 EHTOP_PARAM_DISABLED_SC_BITMAP_PRESENT_IDX,
+			 EHTOP_PARAM_DISABLED_SC_BITMAP_PRESENT_BITS)) {
 		scan_params->channel.puncture_bitmap =
 				QDF_GET_BITS(eht_ops->disable_sub_chan_bitmap[0], 0, 8);
 		scan_params->channel.puncture_bitmap |=
 				QDF_GET_BITS(eht_ops->disable_sub_chan_bitmap[1], 0, 8) << 8;
+	} else {
+		scan_params->channel.puncture_bitmap = 0;
 	}
 
 	return phymode;