Ver código fonte

qca-wifi: Add a new API to exclude channels for preCAC

While excluding the current operating channel for preCAC, the
entire tree is skipped if the current operating channel is selected
by the algorithm. In case of a tree node with two 40MHz nodes, if the
selected channel is the current operating channel but the other 40MHz
channel is still pCAC required, that channel should be selected.

To achieve this, move the logic, of excluding the current operating
channels, inside the tree traversal algorithm.

CRs-Fixed: 2621410
Change-Id: Ib8ea3dea168d27ea98a0bf2a9ea1eb57872b285f
Vignesh Mohan 5 anos atrás
pai
commit
9d35cca695
1 arquivos alterados com 223 adições e 30 exclusões
  1. 223 30
      umac/dfs/core/src/misc/dfs_zero_cac.c

+ 223 - 30
umac/dfs/core/src/misc/dfs_zero_cac.c

@@ -2863,9 +2863,146 @@ void dfs_zero_cac_detach(struct wlan_dfs *dfs)
 	PRECAC_LIST_LOCK_DESTROY(dfs);
 }
 
+/**
+ * dfs_is_pcac_required_for_freq() - Find if given frequency is preCAC required.
+ * @node: Pointer to the preCAC tree Node in which the frequency is present.
+ * @freq: Frequency to be checked.
+ *
+ * Return: False if the frequency is not fully CAC done or in NOL, else true.
+ */
+static bool
+dfs_is_pcac_required_for_freq(struct precac_tree_node *node, uint16_t freq)
+{
+	while (node) {
+		if (node->ch_freq == freq) {
+			if ((node->n_caced_subchs ==
+			     N_SUBCHS_FOR_BANDWIDTH(node->bandwidth)) ||
+			     (node->n_nol_subchs))
+				return false;
+			else
+				return true;
+		}
+		node = dfs_descend_precac_tree_for_freq(node, freq);
+	}
+	return false;
+}
+
+#define DFS_160MHZ_SECSEG_CHAN_FREQ_OFFSET 40
+#ifdef CONFIG_CHAN_NUM_API
+/**
+ * dfs_get_num_cur_subchans_in_node() - Get number of excluded channels
+ *                                      inside the current node.
+ * @dfs:  Pointer to wlan_dfs structure.
+ * @node: Node to be checked.
+ *
+ * Return: uint8_t.
+ * Return the number of excluded (current operating channels in CAC) that are in
+ * the given tree node range.
+ */
+static uint8_t
+dfs_get_num_cur_subchans_in_node(struct wlan_dfs *dfs,
+				 struct precac_tree_node *node)
+{
+	uint16_t exclude_pri_ch_freq, exclude_sec_ch_freq, n_exclude_subchs = 0;
+	uint8_t chwidth_val = DFS_CHWIDTH_80_VAL;
+	struct dfs_channel *curchan = dfs->dfs_curchan;
+
+	exclude_pri_ch_freq =
+		utils_dfs_chan_to_freq(curchan->dfs_ch_vhtop_ch_freq_seg1);
+	exclude_sec_ch_freq =
+		utils_dfs_chan_to_freq(curchan->dfs_ch_vhtop_ch_freq_seg2);
+	if (WLAN_IS_CHAN_MODE_160(curchan)) {
+		if (exclude_sec_ch_freq < exclude_pri_ch_freq)
+			exclude_sec_ch_freq -=
+				DFS_160MHZ_SECSEG_CHAN_FREQ_OFFSET;
+		else
+			exclude_sec_ch_freq +=
+				DFS_160MHZ_SECSEG_CHAN_FREQ_OFFSET;
+	}
+
+	if (WLAN_IS_CHAN_MODE_20(curchan))
+		chwidth_val = DFS_CHWIDTH_20_VAL;
+	else if (WLAN_IS_CHAN_MODE_40(curchan))
+		chwidth_val = DFS_CHWIDTH_40_VAL;
+
+	/* Check if the channel is a subset of the tree node and if it's
+	 * currently in CAC period. This is to avoid excluding channels twice,
+	 * one below and one in the already CACed channels exclusion (in the
+	 * caller API). */
+	if (IS_WITHIN_RANGE(exclude_pri_ch_freq,
+			   node->ch_freq,
+			   (node->bandwidth / 2)) &&
+	   dfs_is_pcac_required_for_freq(node, exclude_pri_ch_freq))
+		n_exclude_subchs += N_SUBCHS_FOR_BANDWIDTH(chwidth_val);
+	if (IS_WITHIN_RANGE(exclude_sec_ch_freq,
+			   node->ch_freq,
+			   (node->bandwidth / 2)) &&
+	   dfs_is_pcac_required_for_freq(node, exclude_sec_ch_freq))
+		n_exclude_subchs += N_SUBCHS_FOR_BANDWIDTH(chwidth_val);
+	return n_exclude_subchs;
+}
+#endif
+
+#ifdef CONFIG_CHAN_FREQ_API
+/**
+ * dfs_get_num_cur_subchans_in_node_freq() - Get number of excluded channels
+ *                                           inside the current node.
+ * @dfs:  Pointer to wlan_dfs structure.
+ * @node: Node to be checked.
+ *
+ * Return: uint8_t.
+ * Return the number of excluded (current operating channels in CAC) that are in
+ * the given tree node range.
+ */
+static uint8_t
+dfs_get_num_cur_subchans_in_node_freq(struct wlan_dfs *dfs,
+				      struct precac_tree_node *node)
+{
+	uint16_t exclude_pri_ch_freq, exclude_sec_ch_freq;
+	uint8_t chwidth_val = DFS_CHWIDTH_80_VAL;
+	uint8_t n_exclude_subchs = 0;
+
+	exclude_pri_ch_freq =
+		dfs->dfs_curchan->dfs_ch_mhz_freq_seg1;
+	exclude_sec_ch_freq =
+		dfs->dfs_curchan->dfs_ch_mhz_freq_seg2;
+	if (WLAN_IS_CHAN_MODE_160(dfs->dfs_curchan)) {
+		if (exclude_sec_ch_freq < exclude_pri_ch_freq)
+			exclude_sec_ch_freq -=
+				DFS_160MHZ_SECSEG_CHAN_OFFSET;
+		else
+			exclude_sec_ch_freq +=
+				DFS_160MHZ_SECSEG_CHAN_OFFSET;
+	}
+
+	if (WLAN_IS_CHAN_MODE_20(dfs->dfs_curchan))
+		chwidth_val = DFS_CHWIDTH_20_VAL;
+	else if (WLAN_IS_CHAN_MODE_40(dfs->dfs_curchan))
+		chwidth_val = DFS_CHWIDTH_40_VAL;
+
+	/* Check if the channel is a subset of the tree node and if it's
+	 * currently in CAC period. This is to avoid excluding channels twice,
+	 * one below and one in the already CACed channels exclusion (in the
+	 * caller API). */
+	if (IS_WITHIN_RANGE(exclude_pri_ch_freq,
+			   node->ch_freq,
+			   (node->bandwidth / 2)) &&
+	   dfs_is_pcac_required_for_freq(node, exclude_pri_ch_freq))
+		n_exclude_subchs += N_SUBCHS_FOR_BANDWIDTH(chwidth_val);
+	if (IS_WITHIN_RANGE(exclude_sec_ch_freq,
+			   node->ch_freq,
+			   (node->bandwidth / 2)) &&
+	   dfs_is_pcac_required_for_freq(node, exclude_sec_ch_freq))
+		n_exclude_subchs += N_SUBCHS_FOR_BANDWIDTH(chwidth_val);
+	return n_exclude_subchs;
+}
+#endif
+
+#ifdef CONFIG_CHAN_NUM_API
 /* dfs_is_cac_needed_for_bst_node() - For a requested bandwidth, find
  *                                    if the current preCAC BSTree node needs
  *                                    CAC.
+ * @dfs:           Pointer to wlan_dfs structure.
  * @node:          Node to be checked.
  * @req_bandwidth: bandwidth of channel requested.
  *
@@ -2874,33 +3011,84 @@ void dfs_zero_cac_detach(struct wlan_dfs *dfs)
  * for the node which is not CAC done, else false.
  */
 static bool
-dfs_is_cac_needed_for_bst_node(struct precac_tree_node *node,
+dfs_is_cac_needed_for_bst_node(struct wlan_dfs *dfs,
+			       struct precac_tree_node *node,
 			       uint8_t req_bandwidth)
 {
-	uint8_t n_subchs_for_req_bw, non_nol_subchs;
+	uint8_t n_subchs_for_req_bw, n_allowed_subchs, n_excluded_subchs;
+
+	if (!node)
+		return false;
+
+	/* Find the number of subchannels for the requested bandwidth */
+	n_excluded_subchs = dfs_get_num_cur_subchans_in_node(dfs, node);
+	n_subchs_for_req_bw = N_SUBCHS_FOR_BANDWIDTH(req_bandwidth);
+	n_allowed_subchs = node->n_valid_subchs -
+			(node->n_nol_subchs + n_excluded_subchs);
+
+	/* Return false if,
+	 * 1. Number of allowed subchannels (all subchannels other than
+	 *    current operating sub-channels and NOL sub-channels) in the
+	 *    current node is less than the requested number of subchannels.
+	 * 3. If the number CAC done subchannels + NOL subchannels + current
+	 *    operating subchannels in the current node is equal to number of
+	 *    valid subchannels in the node.
+	 * else, return true.
+	 */
+	if ((n_allowed_subchs < n_subchs_for_req_bw) ||
+	    ((node->n_caced_subchs + node->n_nol_subchs + n_excluded_subchs) ==
+	     node->n_valid_subchs))
+		return false;
+
+	return true;
+}
+#endif
+
+#ifdef CONFIG_CHAN_FREQ_API
+/* dfs_is_cac_needed_for_bst_node_for_freq() - For a requested bandwidth, find
+ *                                             if the current preCAC BSTree
+ *                                             node needs CAC.
+ * @dfs:           Pointer to wlan_dfs struct.
+ * @node:          Node to be checked.
+ * @req_bandwidth: bandwidth of channel requested.
+ *
+ * Return: TRUE/FALSE.
+ * Return true if there exists a channel of the requested bandwidth
+ * for the node which is not CAC done, else false.
+ */
+static bool
+dfs_is_cac_needed_for_bst_node_for_freq(struct wlan_dfs *dfs,
+					struct precac_tree_node *node,
+					uint8_t req_bandwidth)
+{
+	uint8_t n_subchs_for_req_bw, n_allowed_subchs, n_excluded_subchs;
 
 	if (!node)
 		return false;
 
 	/* Find the number of subchannels for the requested bandwidth */
+	n_excluded_subchs = dfs_get_num_cur_subchans_in_node_freq(dfs, node);
 	n_subchs_for_req_bw = N_SUBCHS_FOR_BANDWIDTH(req_bandwidth);
-	non_nol_subchs = node->n_valid_subchs - node->n_nol_subchs;
+	n_allowed_subchs = node->n_valid_subchs -
+			(node->n_nol_subchs + n_excluded_subchs);
 
 	/* Return false if,
-	 * 1. Number of non-NOL subchannels in the current node is less than
-	 *    the requested number of subchannels.
-	 * 2. All the subchannels of the node are CAC done.
-	 * 3. If the number CAC done subchannels + NOL subchannels in the
-	 *    current node is equal to number of valid subchannels in the node.
+	 * 1. Number of allowed subchannels (all subchannels other than
+	 *    current operating sub-channels and NOL sub-channels) in the
+	 *    current node is less than the requested number of subchannels.
+	 * 3. If the number CAC done subchannels + NOL subchannels + current
+	 *    operating subchannels in the current node is equal to number of
+	 *    valid subchannels in the node.
 	 * else, return true.
 	 */
-	if ((non_nol_subchs < n_subchs_for_req_bw) ||
-	    (node->n_caced_subchs == node->n_valid_subchs) ||
-	    (node->n_caced_subchs + node->n_nol_subchs == node->n_valid_subchs))
+	if ((n_allowed_subchs < n_subchs_for_req_bw) ||
+	    ((node->n_caced_subchs + node->n_nol_subchs + n_excluded_subchs) ==
+	     node->n_valid_subchs))
 		return false;
 
 	return true;
 }
+#endif
 
 /* dfs_find_ieee_ch_from_precac_tree() - from the given preCAC tree, find a IEEE
  *                                       channel of the given bandwidth which
@@ -2914,19 +3102,22 @@ dfs_is_cac_needed_for_bst_node(struct precac_tree_node *node,
  */
 #ifdef CONFIG_CHAN_NUM_API
 static uint8_t
-dfs_find_ieee_ch_from_precac_tree(struct precac_tree_node *root,
+dfs_find_ieee_ch_from_precac_tree(struct wlan_dfs *dfs,
+				  struct precac_tree_node *root,
 				  uint8_t req_bw)
 {
 	struct precac_tree_node *curr_node;
 
-	if (!dfs_is_cac_needed_for_bst_node(root, req_bw))
+	if (!dfs_is_cac_needed_for_bst_node(dfs, root, req_bw))
 		return 0;
 
 	curr_node = root;
 	while (curr_node) {
 		if (curr_node->bandwidth == req_bw) {
 			/* find if current node in valid state (req.) */
-			if (dfs_is_cac_needed_for_bst_node(curr_node, req_bw))
+			if (dfs_is_cac_needed_for_bst_node(dfs,
+							   curr_node,
+							   req_bw))
 				return curr_node->ch_ieee;
 			else
 				return 0;
@@ -2935,7 +3126,8 @@ dfs_find_ieee_ch_from_precac_tree(struct precac_tree_node *root,
 		/* Find if we need to go to left or right subtree.
 		 * Note: If both are available, go to left.
 		 */
-		if (!dfs_is_cac_needed_for_bst_node(curr_node->left_child,
+		if (!dfs_is_cac_needed_for_bst_node(dfs,
+						    curr_node->left_child,
 						    req_bw))
 			curr_node = curr_node->right_child;
 		else
@@ -2958,19 +3150,22 @@ dfs_find_ieee_ch_from_precac_tree(struct precac_tree_node *root,
  */
 #ifdef CONFIG_CHAN_FREQ_API
 static uint16_t
-dfs_find_ieee_ch_from_precac_tree_for_freq(struct precac_tree_node *root,
+dfs_find_ieee_ch_from_precac_tree_for_freq(struct wlan_dfs *dfs,
+					   struct precac_tree_node *root,
 					   uint8_t req_bw)
 {
 	struct precac_tree_node *curr_node;
 
-	if (!dfs_is_cac_needed_for_bst_node(root, req_bw))
+	if (!dfs_is_cac_needed_for_bst_node_for_freq(dfs, root, req_bw))
 		return 0;
 
 	curr_node = root;
 	while (curr_node) {
 		if (curr_node->bandwidth == req_bw) {
 			/* find if current node in valid state (req.) */
-			if (dfs_is_cac_needed_for_bst_node(curr_node, req_bw))
+			if (dfs_is_cac_needed_for_bst_node_for_freq(dfs,
+								    curr_node,
+								    req_bw))
 				return curr_node->ch_freq;
 			else
 				return 0;
@@ -2979,8 +3174,10 @@ dfs_find_ieee_ch_from_precac_tree_for_freq(struct precac_tree_node *root,
 		/* Find if we need to go to left or right subtree.
 		 * Note: If both are available, go to left.
 		 */
-		if (!dfs_is_cac_needed_for_bst_node(curr_node->left_child,
-						    req_bw))
+		if (!dfs_is_cac_needed_for_bst_node_for_freq(
+				dfs,
+				curr_node->left_child,
+				req_bw))
 			curr_node = curr_node->right_child;
 		else
 			curr_node = curr_node->left_child;
@@ -3011,13 +3208,11 @@ uint8_t dfs_get_ieeechan_for_precac(struct wlan_dfs *dfs,
 			      pe_list) {
 			root = precac_entry->tree_root;
 			ieee_chan =
-				dfs_find_ieee_ch_from_precac_tree(root,
+				dfs_find_ieee_ch_from_precac_tree(dfs,
+								  root,
 								  bandwidth);
-			if (ieee_chan &&
-			    (ieee_chan != exclude_pri_ch_ieee) &&
-			    (ieee_chan != exclude_sec_ch_ieee))
+			if (ieee_chan)
 				break;
-			ieee_chan = 0;
 		}
 	}
 	PRECAC_LIST_UNLOCK(dfs);
@@ -3056,13 +3251,11 @@ uint16_t dfs_get_ieeechan_for_precac_for_freq(struct wlan_dfs *dfs,
 			      pe_list) {
 			root = precac_entry->tree_root;
 			ieee_chan_freq =
-				dfs_find_ieee_ch_from_precac_tree_for_freq(root,
+				dfs_find_ieee_ch_from_precac_tree_for_freq(dfs,
+									   root,
 									   bw);
-			if (ieee_chan_freq &&
-			    (ieee_chan_freq != exclude_pri_ch_freq) &&
-			    (ieee_chan_freq != exclude_sec_ch_freq))
+			if (ieee_chan_freq)
 				break;
-			ieee_chan_freq = 0;
 		}
 	}
 	PRECAC_LIST_UNLOCK(dfs);