Browse Source

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

Linux Build Service Account 5 years ago
parent
commit
332fe12c3c
1 changed files with 223 additions and 30 deletions
  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);