Jelajahi Sumber

qca-wifi: Add support for 160MHz precac tree

Rebuild the precac tree with 160MHz root channels. Add support to mark the
160MHz precac channel nodes as CAC done and NOL.

Go through the list of available channels to find the unique PreCAC Tree
roots. Find the root channels that are not part of the 160MHz channel.
Example, consider a case where a country supports only until channel 144,
then the precac tree will have two 160MHz root nodes(36HT160, 100HT160) and
one 80MHz root node(132HT80).

Add support include the 165MHz channel to the precac tree for Pine by
considering the 165MHz channel as a 80p80MHz channel with a center channel
number 146. Adjust the channel frequency offset to mark the 165MHz
channel as precac done and NOL.

When a 160MHz or the 165MHz channel encloses a nonDFS channel, mark that
nonDFS channel as precac done.

Change-Id: Ia9bb2cc5c845c4d636e35329cdf76ace2eb63c72
CRs-Fixed: 2628373
Vignesh U 5 tahun lalu
induk
melakukan
a5540082df
1 mengubah file dengan 440 tambahan dan 103 penghapusan
  1. 440 103
      umac/dfs/core/src/misc/dfs_zero_cac.c

+ 440 - 103
umac/dfs/core/src/misc/dfs_zero_cac.c

@@ -488,8 +488,9 @@ static bool dfs_find_cac_status_for_chan(struct dfs_precac_entry *precac_entry,
  *				    Return true if CAC done, else false.
  * @dfs_precac_entry: Precac entry which has the root of the precac BSTree.
  * @chan_freq:        IEEE channel freq. This is the center of a
- *                    20/40/80 MHz channel and the center channel is unique
- *                    irrespective of the bandwidth(20/40/80 MHz).
+ *                    20/40/80/160/165 MHz channel and the center channel is
+ *                    unique irrespective of the bandwidth
+ *                    (20/40/80/160/165 MHz).
  */
 #ifdef CONFIG_CHAN_FREQ_API
 static bool
@@ -497,7 +498,7 @@ dfs_find_cac_status_for_chan_for_freq(struct dfs_precac_entry *precac_entry,
 				      uint16_t chan_freq)
 {
 	struct precac_tree_node *node = precac_entry->tree_root;
-	uint8_t n_cur_lvl_subchs = N_SUBCHANS_FOR_80BW;
+	uint8_t n_cur_lvl_subchs = N_SUBCHANS_FOR_160BW;
 
 	while (node) {
 		if (node->ch_freq == chan_freq)
@@ -517,6 +518,12 @@ dfs_find_cac_status_for_chan_for_freq(struct dfs_precac_entry *precac_entry,
 
 #ifdef CONFIG_CHAN_FREQ_API
 #define VHT80_FREQ_OFFSET 30
+/* For any 160MHz channel, a frequency offset of 70MHz would have been enough
+ * to include the right edge and left edge channels. But, the restricted 80P80
+ * or the 165MHz channel is also assumed to have a 160MHz root ie channel 146,
+ * so an offset of 75MHz is chosen.
+ */
+#define VHT160_FREQ_OFFSET 75
 #endif
 
 #define IS_WITHIN_RANGE(_A, _B, _C)  \
@@ -1261,8 +1268,8 @@ void dfs_mark_precac_done_for_freq(struct wlan_dfs *dfs,
 				   pe_list,
 				   tmp_precac_entry) {
 			if (IS_WITHIN_RANGE(channels[i],
-					    precac_entry->vht80_ch_freq,
-					    VHT80_FREQ_OFFSET)) {
+					    precac_entry->center_ch_freq,
+					    VHT160_FREQ_OFFSET)) {
 				dfs_mark_tree_node_as_cac_done_for_freq
 					(dfs, precac_entry, channels[i]);
 				break;
@@ -1735,8 +1742,8 @@ void dfs_mark_precac_nol_for_freq(struct wlan_dfs *dfs,
 				   pe_list,
 				   tmp_precac_entry) {
 			if (IS_WITHIN_RANGE(freq_lst[i],
-					    precac_entry->vht80_ch_freq,
-					    VHT80_FREQ_OFFSET)) {
+					    precac_entry->center_ch_freq,
+					    VHT160_FREQ_OFFSET)) {
 				dfs_mark_tree_node_as_nol_for_freq(dfs,
 								   precac_entry,
 								   freq_lst[i]);
@@ -2158,10 +2165,20 @@ static os_timer_func(dfs_precac_timeout)
 		     current_time / 1000);
 	    if (dfs_soc_obj->ocac_status == OCAC_SUCCESS) {
 		dfs_soc_obj->ocac_status = OCAC_RESET;
-		dfs_mark_precac_done_for_freq(dfs,
-					      dfs->dfs_agile_precac_freq_mhz,
-					      0,
-					      dfs->dfs_precac_chwidth);
+		if (dfs->dfs_agile_precac_freq_mhz ==
+		    RESTRICTED_80P80_CHAN_CENTER_FREQ) {
+			dfs_mark_precac_done_for_freq(
+				dfs,
+				RESTRICTED_80P80_LEFT_80_CENTER_FREQ,
+				RESTRICTED_80P80_RIGHT_80_CENTER_FREQ,
+				CH_WIDTH_80P80MHZ);
+		} else {
+			dfs_mark_precac_done_for_freq(
+				dfs,
+				dfs->dfs_agile_precac_freq_mhz,
+				0,
+				dfs->dfs_precac_chwidth);
+		}
 	    }
 	    /* check if CAC done on home channel */
 	    is_cac_done_on_des_chan = dfs_precac_check_home_chan_change(dfs);
@@ -2295,12 +2312,15 @@ static inline void dfs_init_precac_tree_node(struct precac_tree_node *node,
  * @node:      Precac_tree_node to be filled.
  * @freq:      IEEE channel freq value.
  * @bandwidth: Bandwidth of the channel.
+ * @depth:     Depth of the tree. The depth of the tree when the root is 160MHz
+ *             channel is 4, 80MHz is 3, 40MHz is 2 and 20MHz is 1.
  */
 #ifdef CONFIG_CHAN_FREQ_API
 static inline void
 dfs_init_precac_tree_node_for_freq(struct precac_tree_node *node,
 				   uint16_t freq,
-				   uint8_t bandwidth)
+				   uint8_t bandwidth,
+				   uint8_t depth)
 {
 	node->left_child = NULL;
 	node->right_child = NULL;
@@ -2310,6 +2330,8 @@ dfs_init_precac_tree_node_for_freq(struct precac_tree_node *node,
 	node->n_nol_subchs = 0;
 	node->n_valid_subchs = N_SUBCHS_FOR_BANDWIDTH(bandwidth);
 	node->bandwidth = bandwidth;
+	node->depth = depth;
+
 }
 #endif
 
@@ -2364,6 +2386,8 @@ dfs_insert_node_into_bstree(struct precac_tree_node **root,
  * @root:      The preCAC BSTree root pointer.
  * @chan:      IEEE freq of the new node.
  * @bandwidth: Bandwidth of the channel.
+ * @depth:     Depth of the tree. The depth of the tree when the root is 160MHz
+ *             channel is 4, 80MHz is 3, 40MHz is 2 and 20MHz is 1.
  *
  * Return: EOK if new node is allocated, else return ENOMEM.
  */
@@ -2371,7 +2395,8 @@ dfs_insert_node_into_bstree(struct precac_tree_node **root,
 static QDF_STATUS
 dfs_insert_node_into_bstree_for_freq(struct precac_tree_node **root,
 				     uint16_t chan_freq,
-				     uint8_t bandwidth)
+				     uint8_t bandwidth,
+				     uint8_t depth)
 {
 	struct precac_tree_node *new_node = NULL;
 	struct precac_tree_node *curr_node, *prev_node = NULL;
@@ -2380,7 +2405,10 @@ dfs_insert_node_into_bstree_for_freq(struct precac_tree_node **root,
 	new_node = qdf_mem_malloc(sizeof(*new_node));
 	if (!new_node)
 		return -ENOMEM;
-	dfs_init_precac_tree_node_for_freq(new_node, chan_freq, bandwidth);
+	dfs_init_precac_tree_node_for_freq(new_node,
+					   chan_freq,
+					   bandwidth,
+					   depth);
 
 	/* If root node is null, assign the newly allocated node
 	 * to this node and return.
@@ -2439,13 +2467,13 @@ dfs_create_precac_tree(struct wlan_dfs *dfs,
 	struct precac_tree_node *root = NULL;
 	int chan, i, bandwidth = DFS_CHWIDTH_80_VAL;
 	QDF_STATUS status = EOK;
-	static const int initial_and_next_offsets[TREE_DEPTH][N_OFFSETS] = {
+	static const int initial_and_next_offsets[TREE_DEPTH_MAX][N_OFFSETS] = {
 		{INITIAL_80_CHAN_OFFSET, NEXT_80_CHAN_OFFSET},
 		{INITIAL_40_CHAN_OFFSET, NEXT_40_CHAN_OFFSET},
 		{INITIAL_20_CHAN_OFFSET, NEXT_20_CHAN_OFFSET}
 	};
 
-	for (i = 0; i < TREE_DEPTH; i++) {
+	for (i = 0; i < TREE_DEPTH_MAX; i++) {
 		/* In offset array,
 		 * column 0 is initial chan offset,
 		 * column 1 is next chan offset.
@@ -2473,59 +2501,347 @@ dfs_create_precac_tree(struct wlan_dfs *dfs,
 }
 #endif
 
+#ifdef CONFIG_CHAN_FREQ_API
+/**
+ * struct precac_tree_offset_for_different_bw - Bandwidth, tree depth and
+ * channel offsets information to build the precac tree.
+ * @bandwidth:                Bandwidth of the the root node.
+ * @tree_depth:               Tree depth of the precac tree.
+ * @initial_and_next_offsets: Offset to root node to find the initial and the
+ *                            next channels of the node.
+ */
+struct precac_tree_offset_for_different_bw {
+	int bandwidth;
+	int tree_depth;
+	int initial_and_next_offsets[TREE_DEPTH_MAX][N_OFFSETS];
+};
+
+static const
+struct precac_tree_offset_for_different_bw offset20 = {DFS_CHWIDTH_20_VAL,
+	TREE_DEPTH_20,
+	{
+		{0, NEXT_20_CHAN_FREQ_OFFSET}
+	}
+};
+
+static const
+struct precac_tree_offset_for_different_bw offset40 = {DFS_CHWIDTH_40_VAL,
+	TREE_DEPTH_40,
+	{
+		{0, NEXT_40_CHAN_FREQ_OFFSET},
+		{-10, NEXT_20_CHAN_FREQ_OFFSET}
+	}
+};
+
+static const
+struct precac_tree_offset_for_different_bw offset80 = {DFS_CHWIDTH_80_VAL,
+	TREE_DEPTH_80,
+	{
+		{0, NEXT_80_CHAN_FREQ_OFFSET},
+		{-20, NEXT_40_CHAN_FREQ_OFFSET},
+		{-30, NEXT_20_CHAN_FREQ_OFFSET}
+	}
+};
+
+static const
+struct precac_tree_offset_for_different_bw offset160 = {DFS_CHWIDTH_160_VAL,
+	TREE_DEPTH_160,
+	{
+		{INITIAL_160_CHAN_FREQ_OFFSET, NEXT_160_CHAN_FREQ_OFFSET},
+		{INITIAL_80_CHAN_FREQ_OFFSET, NEXT_80_CHAN_FREQ_OFFSET},
+		{INITIAL_40_CHAN_FREQ_OFFSET, NEXT_40_CHAN_FREQ_OFFSET},
+		{INITIAL_20_CHAN_FREQ_OFFSET, NEXT_20_CHAN_FREQ_OFFSET}
+	}
+};
+
+static const
+struct precac_tree_offset_for_different_bw default_offset = {0, 0};
+
 /* dfs_create_precac_tree_for_freq() - Fill precac entry tree (level insertion).
- * @dfs:     WLAN DFS structure
- * @ch_freq: root_node freq.
+ * @dfs:       WLAN DFS structure
+ * @ch_freq:   root_node freq.
+ * @root:      Pointer to the node that will be filled and inserted as tree
+ *             root.
+ * @bandwidth: Bandwidth value of the root.
  */
-#ifdef CONFIG_CHAN_FREQ_API
 static QDF_STATUS
 dfs_create_precac_tree_for_freq(struct wlan_dfs *dfs,
-				struct dfs_precac_entry *precac_entry,
-				uint16_t ch_freq)
+				uint16_t ch_freq,
+				struct precac_tree_node **root,
+				int bandwidth)
 {
-	struct precac_tree_node *root = NULL;
-	int chan_freq, i, bandwidth = DFS_CHWIDTH_80_VAL;
+	int chan_freq, i;
 	QDF_STATUS status = EOK;
-	static const int initial_and_next_offsets[TREE_DEPTH][N_OFFSETS] = {
-		{INITIAL_80_CHAN_FREQ_OFFSET, NEXT_80_CHAN_FREQ_OFFSET},
-		{INITIAL_40_CHAN_FREQ_OFFSET, NEXT_40_CHAN_FREQ_OFFSET},
-		{INITIAL_20_CHAN_FREQ_OFFSET, NEXT_20_CHAN_FREQ_OFFSET}
-	};
+	struct precac_tree_offset_for_different_bw current_mode;
+	uint8_t top_lvl_step;
+	bool is_node_part_of_165_tree = false;
 
-	for (i = 0; i < TREE_DEPTH; i++) {
+	if (ch_freq == RESTRICTED_80P80_LEFT_80_CENTER_FREQ ||
+	    ch_freq == RESTRICTED_80P80_RIGHT_80_CENTER_FREQ)
+		is_node_part_of_165_tree = true;
+
+	switch (bandwidth) {
+	case DFS_CHWIDTH_160_VAL:
+			current_mode = offset160;
+			break;
+	case DFS_CHWIDTH_80_VAL:
+			current_mode = offset80;
+			break;
+	case DFS_CHWIDTH_40_VAL:
+			current_mode = offset40;
+			break;
+	case DFS_CHWIDTH_20_VAL:
+			current_mode = offset20;
+			break;
+	default:
+			current_mode = default_offset;
+			break;
+	}
+	top_lvl_step = current_mode.initial_and_next_offsets[0][1];
+	for (i = 0; i < current_mode.tree_depth; i++) {
 		/* In offset array,
 		 * column 0 is initial chan offset,
 		 * column 1 is next chan offset.
 		 * Boundary offset is initial offset and next offset
 		 * of root level (since root level can have only 1 node)
 		 */
-		int offset = initial_and_next_offsets[i][START_INDEX];
-		int step = initial_and_next_offsets[i][STEP_INDEX];
-		uint8_t top_lvl_step = NEXT_80_CHAN_FREQ_OFFSET;
+		int offset =
+		    current_mode.initial_and_next_offsets[i][START_INDEX];
+		int step = current_mode.initial_and_next_offsets[i][STEP_INDEX];
 		int boundary_offset = offset + top_lvl_step;
+		uint8_t depth = is_node_part_of_165_tree ? i + 1 : i;
 
 		for (; offset < boundary_offset; offset += step) {
 			chan_freq = (int)ch_freq + offset;
 			status =
-			    dfs_insert_node_into_bstree_for_freq(&root,
+			    dfs_insert_node_into_bstree_for_freq(root,
 								 chan_freq,
-								 bandwidth);
+								 bandwidth,
+								 depth);
 			if (status)
 				return status;
 		}
 		bandwidth /= 2;
 	}
 
-	precac_entry->tree_root = root;
 	return status;
 }
 #endif
 
+#ifdef CONFIG_CHAN_FREQ_API
+/**
+ * struct dfs_channel_bw - Structure to store the information about precac
+ * root's primary channel frequency, maximum bandwidth and the center frequency.
+ *
+ * @dfs_pri_ch_freq:     Primary channel frequency of the root channel.
+ * @dfs_center_ch_freq:  Center frequency of the 20/40/80/160 channel.In case of
+ *                       the 165MHz channel, it is 5730MHz.
+ * @dfs_max_bw:          Maximum bandwidth of the channel available in the
+ *                       current channel list.
+ */
+struct dfs_channel_bw {
+	uint16_t dfs_pri_ch_freq;
+	uint16_t dfs_center_ch_freq;
+	uint16_t dfs_max_bw;
+};
+
+static void
+dfs_calculate_bw_for_same_pri_ch(struct wlan_dfs *dfs,
+				 struct dfs_channel_bw *dfs_max_bw_info,
+				 int index,
+				 struct dfs_channel *ichan,
+				 int *delimiter)
+{
+	uint8_t temp_bw = 0;
+
+	dfs_max_bw_info[index].dfs_pri_ch_freq = ichan->dfs_ch_freq;
+	dfs_max_bw_info[index].dfs_center_ch_freq = ichan->dfs_ch_mhz_freq_seg1;
+
+	if (WLAN_IS_CHAN_MODE_20(ichan)) {
+		temp_bw = DFS_CHWIDTH_20_VAL;
+	} else if (WLAN_IS_CHAN_MODE_40(ichan)) {
+		temp_bw = DFS_CHWIDTH_40_VAL;
+	} else if (WLAN_IS_CHAN_MODE_80(ichan) ||
+		   WLAN_IS_CHAN_MODE_80_80(ichan)) {
+		temp_bw = DFS_CHWIDTH_80_VAL;
+	if (dfs_is_restricted_80p80mhz_supported(dfs) &&
+	    WLAN_IS_PRIMARY_OR_SECONDARY_CHAN_DFS(ichan) &&
+	    (ichan->dfs_ch_vhtop_ch_freq_seg1 ==
+	     RESTRICTED_80P80_LEFT_80_CENTER_CHAN) &&
+	    (ichan->dfs_ch_vhtop_ch_freq_seg2 ==
+	     RESTRICTED_80P80_RIGHT_80_CENTER_CHAN)) {
+		temp_bw = DFS_CHWIDTH_165_VAL;
+		dfs_max_bw_info[index].dfs_center_ch_freq =
+			RESTRICTED_80P80_CHAN_CENTER_FREQ;
+		}
+	} else if (WLAN_IS_CHAN_MODE_160(ichan)) {
+		temp_bw = DFS_CHWIDTH_160_VAL;
+		dfs_max_bw_info[index].dfs_center_ch_freq =
+			ichan->dfs_ch_mhz_freq_seg2;
+	}
+	if (temp_bw > dfs_max_bw_info[index].dfs_max_bw)
+		dfs_max_bw_info[index].dfs_max_bw = temp_bw;
+	*delimiter = dfs_max_bw_info[index].dfs_pri_ch_freq +
+	dfs_max_bw_info[index].dfs_max_bw;
+}
+
+/* dfs_fill_max_bw_for_chan() - Finds unique precac tree node in the channel
+ * list and stores the primary channel frequency, maximum bandwidth and the
+ * center frequency. The algorithm is based on the data structure ic_channels
+ * where the channels are organized as 36HT20, 36HT40, 36HT80,... and so on..
+ * @dfs:               WLAN DFS structure
+ * @dfs_max_bw_info:   Structure to store precac tree root channel's
+ * information.
+ * @num_precac_roots:  Number of unique.
+ */
+static void dfs_fill_max_bw_for_chan(struct wlan_dfs *dfs,
+				     struct dfs_channel_bw *dfs_max_bw_info,
+				     int *num_precac_roots)
+{
+	int nchans = 0, i, j = 0, prev_ch_freq = 0, delimiter = 0;
+
+	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
+	for (i = 0; i < nchans; i++) {
+		struct dfs_channel *ichan = NULL, lc;
+
+		ichan = &lc;
+		dfs_mlme_get_dfs_channels_for_freq
+			(dfs->dfs_pdev_obj,
+			 &ichan->dfs_ch_freq,
+			 &ichan->dfs_ch_flags,
+			 &ichan->dfs_ch_flagext,
+			 &ichan->dfs_ch_ieee,
+			 &ichan->dfs_ch_vhtop_ch_freq_seg1,
+			 &ichan->dfs_ch_vhtop_ch_freq_seg2,
+			 &ichan->dfs_ch_mhz_freq_seg1,
+			 &ichan->dfs_ch_mhz_freq_seg2,
+			 i);
+		if (!WLAN_IS_PRIMARY_OR_SECONDARY_CHAN_DFS(ichan))
+			continue;
+		if (ichan->dfs_ch_freq == prev_ch_freq) {
+			dfs_calculate_bw_for_same_pri_ch(dfs,
+							 dfs_max_bw_info,
+							 j,
+							 ichan,
+							 &delimiter);
+		} else if (ichan->dfs_ch_freq < delimiter) {
+			continue;
+		} else {
+			prev_ch_freq = ichan->dfs_ch_freq;
+			j++;
+		}
+	}
+	*num_precac_roots = j + 1;
+}
+
+static QDF_STATUS
+dfs_precac_create_precac_entry(struct wlan_dfs *dfs,
+			       struct dfs_precac_entry *precac_entry,
+			       struct dfs_channel_bw *dfs_max_bw_info,
+			       int index)
+{
+	QDF_STATUS status;
+	uint16_t precac_center_freq =
+	    dfs_max_bw_info[index].dfs_center_ch_freq;
+
+	precac_entry->center_ch_freq = precac_center_freq;
+	precac_entry->center_ch_ieee =
+	utils_dfs_freq_to_chan(precac_center_freq);
+	precac_entry->bw = dfs_max_bw_info[index].dfs_max_bw;
+	precac_entry->dfs = dfs;
+	status =
+	    dfs_create_precac_tree_for_freq(dfs,
+					    precac_entry->center_ch_freq,
+					    &precac_entry->tree_root,
+					    precac_entry->bw);
+	if (status) {
+		dfs_debug(dfs, WLAN_DEBUG_DFS,
+			  "PreCAC entry for channel %d not created",
+			  precac_entry->center_ch_ieee);
+	} else {
+	    TAILQ_INSERT_TAIL(
+		    &dfs->dfs_precac_list,
+		    precac_entry, pe_list);
+	}
+	return status;
+}
+
+static QDF_STATUS
+dfs_precac_create_165mhz_precac_entry(struct wlan_dfs *dfs,
+				      struct dfs_precac_entry *precac_entry)
+{
+	QDF_STATUS status;
+
+	precac_entry->center_ch_freq =
+		RESTRICTED_80P80_CHAN_CENTER_FREQ;
+	precac_entry->center_ch_ieee =
+		utils_dfs_freq_to_chan(precac_entry->center_ch_freq);
+	precac_entry->bw = DFS_CHWIDTH_160_VAL;
+	precac_entry->dfs = dfs;
+	dfs_insert_node_into_bstree_for_freq(&precac_entry->tree_root,
+					     RESTRICTED_80P80_CHAN_CENTER_FREQ,
+					     DFS_CHWIDTH_160_VAL,
+					     DEPTH_160_ROOT);
+	status =
+		dfs_create_precac_tree_for_freq
+		(dfs,
+					RESTRICTED_80P80_LEFT_80_CENTER_FREQ,
+					&precac_entry->tree_root->left_child,
+					DFS_CHWIDTH_80_VAL);
+	if (!status)
+		status =
+		    dfs_create_precac_tree_for_freq(
+			    dfs,
+			    RESTRICTED_80P80_RIGHT_80_CENTER_FREQ,
+			    &precac_entry->tree_root->right_child,
+			    DFS_CHWIDTH_80_VAL);
+	TAILQ_INSERT_TAIL(
+			&dfs->dfs_precac_list,
+			precac_entry, pe_list);
+	return status;
+}
+
+static void
+dfs_mark_non_dfs_as_precac_done(struct wlan_dfs *dfs,
+				uint16_t dfs_pri_ch_freq,
+				enum wlan_phymode mode)
+{
+	struct dfs_channel *ichan, lc;
+
+	ichan = &lc;
+	dfs_mlme_find_dot11_chan_for_freq(dfs->dfs_pdev_obj,
+					  dfs_pri_ch_freq,
+					  0,
+					  mode,
+					  &ichan->dfs_ch_freq,
+					  &ichan->dfs_ch_flags,
+					  &ichan->dfs_ch_flagext,
+					  &ichan->dfs_ch_ieee,
+					  &ichan->dfs_ch_vhtop_ch_freq_seg1,
+					  &ichan->dfs_ch_vhtop_ch_freq_seg2,
+					  &ichan->dfs_ch_mhz_freq_seg1,
+					  &ichan->dfs_ch_mhz_freq_seg2);
+	if (!WLAN_IS_CHAN_DFS(ichan)) {
+		PRECAC_LIST_UNLOCK(dfs);
+		dfs_mark_precac_done_for_freq(dfs,
+					      ichan->dfs_ch_mhz_freq_seg1,
+					      0,
+					      CH_WIDTH_80MHZ);
+		PRECAC_LIST_LOCK(dfs);
+	} else if (!WLAN_IS_CHAN_DFS_CFREQ2(ichan)) {
+		PRECAC_LIST_UNLOCK(dfs);
+		dfs_mark_precac_done_for_freq(dfs,
+					      ichan->dfs_ch_mhz_freq_seg2,
+					      0,
+					      CH_WIDTH_80MHZ);
+		PRECAC_LIST_LOCK(dfs);
+	}
+}
+
 /*
  * dfs_init_precac_list() - Initialize preCAC lists.
  * @dfs: Pointer to wlan_dfs.
  */
-#ifdef CONFIG_CHAN_FREQ_API
 void dfs_init_precac_list(struct wlan_dfs *dfs)
 {
 	u_int i;
@@ -2533,6 +2849,8 @@ void dfs_init_precac_list(struct wlan_dfs *dfs)
 	struct dfs_precac_entry *tmp_precac_entry;
 	int nchans = 0;
 	QDF_STATUS status;
+	struct dfs_channel_bw *dfs_max_bw_info;
+	int num_precac_roots;
 
 	/* Right now, only ETSI domain supports preCAC. Check if current
 	 * DFS domain is ETSI and only then build the preCAC list.
@@ -2541,88 +2859,99 @@ void dfs_init_precac_list(struct wlan_dfs *dfs)
 		return;
 
 	/*
-	 * We need to prepare list of uniq VHT80 center frequencies. But at the
-	 * beginning we do not know how many uniq frequencies are present.
-	 * Therefore, we calculate the MAX size and allocate a temporary
-	 * list/array. However we fill the temporary array with uniq frequencies
-	 * and copy the uniq list of frequencies to the final list with exact
-	 * size.
+	 * We need to prepare list of uniquee center frequencies of maximum
+	 * possible bandwidths. But at the beginning we do not know how many
+	 * unique frequencies are present. Therefore, we calculate the MAX size
+	 * and allocate a temporary list/array. However we fill the temporary
+	 * array with unique frequencies and copy the unique list of frequencies
+	 * to the final list with exact size.
 	 */
-	TAILQ_INIT(&dfs->dfs_precac_list);
 	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
+	dfs_max_bw_info = qdf_mem_malloc(nchans *
+		sizeof(struct dfs_channel_bw));
+	if (!dfs_max_bw_info) {
+		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
+			"memory allocation failed");
+		return;
+	}
+	dfs_fill_max_bw_for_chan(dfs, dfs_max_bw_info, &num_precac_roots);
 
-	PRECAC_LIST_LOCK(dfs);
-	/* Fill the  precac_list with unique elements */
-	for (i = 0; i < nchans; i++) {
-		struct dfs_channel *ichan = NULL, lc;
-		uint16_t pri_chan_cfreq = 0;
+	TAILQ_INIT(&dfs->dfs_precac_list);
 
-		ichan = &lc;
-		dfs_mlme_get_dfs_channels_for_freq
-			(dfs->dfs_pdev_obj,
-			 &ichan->dfs_ch_freq,
-			 &ichan->dfs_ch_flags,
-			 &ichan->dfs_ch_flagext,
-			 &ichan->dfs_ch_ieee,
-			 &ichan->dfs_ch_vhtop_ch_freq_seg1,
-			 &ichan->dfs_ch_vhtop_ch_freq_seg2,
-			 &ichan->dfs_ch_mhz_freq_seg1,
-			 &ichan->dfs_ch_mhz_freq_seg2,
-			 i);
-		pri_chan_cfreq = ichan->dfs_ch_mhz_freq_seg1;
+	PRECAC_LIST_LOCK(dfs);
+	for (i = 0; i < num_precac_roots; i++) {
+		uint16_t pri_chan_cfreq = dfs_max_bw_info[i].dfs_center_ch_freq;
 
-		if (WLAN_IS_CHAN_11AC_VHT80(ichan) &&
-		    WLAN_IS_CHAN_DFS(ichan)) {
-			found = 0;
-			TAILQ_FOREACH(tmp_precac_entry,
-				      &dfs->dfs_precac_list,
-				      pe_list) {
-				if (tmp_precac_entry->vht80_ch_freq ==
-				    pri_chan_cfreq) {
-					found = 1;
-					break;
-				}
+		found = 0;
+		TAILQ_FOREACH(tmp_precac_entry,
+			      &dfs->dfs_precac_list,
+			      pe_list) {
+			if (tmp_precac_entry->center_ch_freq ==
+					pri_chan_cfreq) {
+				found = 1;
+				break;
 			}
-			if (!found && pri_chan_cfreq) {
-				struct dfs_precac_entry *precac_entry;
+		}
+		if (!found && pri_chan_cfreq) {
+			struct dfs_precac_entry *precac_entry;
 
-				precac_entry =
-					qdf_mem_malloc(sizeof(*precac_entry));
-				if (!precac_entry) {
-					dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
-						"entry alloc fail for : %d", i);
-					continue;
-				}
-				precac_entry->vht80_ch_freq =
-					pri_chan_cfreq;
-				precac_entry->vht80_ch_ieee =
-					utils_dfs_freq_to_chan(pri_chan_cfreq);
-				precac_entry->dfs = dfs;
-				status =
-					dfs_create_precac_tree_for_freq
-					(dfs, precac_entry, pri_chan_cfreq);
+			precac_entry =
+				qdf_mem_malloc(sizeof(*precac_entry));
+			if (!precac_entry) {
+				dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
+					"entry alloc fail for : %d", i);
+				continue;
+			}
+			if (dfs_max_bw_info[i].dfs_max_bw ==
+				DFS_CHWIDTH_165_VAL) {
+				status = dfs_precac_create_165mhz_precac_entry(
+						dfs,
+						precac_entry);
 				if (status) {
-					dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
-						"tree_node alloc failed");
+					dfs_debug(dfs,
+						  WLAN_DEBUG_DFS,
+						  "PreCAC entry for channel 146 not created");
 					continue;
 				}
-				TAILQ_INSERT_TAIL(
-						  &dfs->dfs_precac_list,
-						  precac_entry, pe_list);
+			    /* The restricted 80p80 or the 165MHz channel might
+			     * have a non DFS part with center frequency 5775.
+			     * Mark the non DFS portion as precac done.
+			     */
+			    dfs_mark_non_dfs_as_precac_done(
+				    dfs,
+				    dfs_max_bw_info[i].dfs_pri_ch_freq,
+				    WLAN_PHYMODE_11AC_VHT80_80);
+			} else {
+			    status =
+				dfs_precac_create_precac_entry(dfs,
+							       precac_entry,
+							       dfs_max_bw_info,
+							       i);
+			if (status)
+				continue;
+			/* Some channels like 36HT160 might have a non DFS
+			 * part. Mark the non DFS portion as precac done.
+			 */
+			dfs_mark_non_dfs_as_precac_done(
+				dfs,
+				dfs_max_bw_info[i].dfs_pri_ch_freq,
+				WLAN_PHYMODE_11AC_VHT160);
 			}
 		}
 	}
 	PRECAC_LIST_UNLOCK(dfs);
+	qdf_mem_free(dfs_max_bw_info);
 
 	dfs_debug(dfs, WLAN_DEBUG_DFS,
-		  "Print the list of VHT80 frequencies from linked list");
+		  "Print the list of PreCAC ieee chan from linked list");
 	TAILQ_FOREACH(tmp_precac_entry,
 		      &dfs->dfs_precac_list,
 		      pe_list) {
-	    uint8_t ch_ieee;
+	    uint8_t ch_ieee, bw;
 
-	    ch_ieee = utils_dfs_freq_to_chan(tmp_precac_entry->vht80_ch_freq);
-	    dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "ieee=%u", ch_ieee);
+	    ch_ieee = utils_dfs_freq_to_chan(tmp_precac_entry->center_ch_freq);
+	    bw = tmp_precac_entry->bw;
+	    dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "ieee=%u bw=%u", ch_ieee, bw);
 	}
 }
 #else
@@ -3663,7 +3992,7 @@ void dfs_start_precac_timer_for_freq(struct wlan_dfs *dfs,
  * based on the level (and by our logic, bandwidth) of the current node.
  *
  */
-#define MAX_PREFIX_CHAR 20
+#define MAX_PREFIX_CHAR 28
 /*Retaining IEEE to print node data */
 static void dfs_print_node_data(struct wlan_dfs *dfs,
 				struct precac_tree_node *node)
@@ -3672,17 +4001,25 @@ static void dfs_print_node_data(struct wlan_dfs *dfs,
 	char prev_line_prefix[MAX_PREFIX_CHAR] = "";
 	char inv[4] = "inv";
 
-	switch (node->bandwidth) {
-	case DFS_CHWIDTH_80_VAL:
+	switch (node->depth) {
+	case DEPTH_160_ROOT:
 		break;
-	case DFS_CHWIDTH_40_VAL:
+	case DEPTH_80_ROOT:
 		qdf_str_lcopy(prev_line_prefix, "|", MAX_PREFIX_CHAR);
 		qdf_str_lcopy(prefix, "|------- ", MAX_PREFIX_CHAR);
 		break;
-	case DFS_CHWIDTH_20_VAL:
+	case DEPTH_40_ROOT:
 		qdf_str_lcopy(prev_line_prefix, "|        |", MAX_PREFIX_CHAR);
 		qdf_str_lcopy(prefix, "|        |------- ", MAX_PREFIX_CHAR);
 		break;
+	case DEPTH_20_ROOT:
+		qdf_str_lcopy(prev_line_prefix,
+			      "|        |        |",
+			      MAX_PREFIX_CHAR);
+		qdf_str_lcopy(prefix,
+			      "|        |        |------- ",
+			      MAX_PREFIX_CHAR);
+		break;
 	default:
 		return;
 	}