Parcourir la source

qcacmn: Keep bonded channels enabled for SET_FCC_CHANNEL 0/2

Currently host disables all 6 GHz channels and keeps only
STA connected channel enabled. If STA bandwidth is greater
than 20 MHz kernel send disconnect as the bonded channels
are disabled.
Similarly for STA + SAP SCC case, if STA bandwidth is
20 MHz and SAP bandwidth is greater than 20 MHz kernel
sends stop_ap as the bonded channels are disabled.

To address above scenarios, for standalone STA case
keep the bonded channels enabled and for STA + SAP
SCC case keep the bonded channels enabled for STA and
SAP.

Change-Id: I1c4f7fea139ca36f5a61cc514eff779801db57ae
CRs-Fixed: 3580015
Asutosh Mohapatra il y a 1 an
Parent
commit
b1ca37af64

+ 197 - 40
umac/regulatory/core/src/reg_build_chan_list.c

@@ -37,6 +37,7 @@
 #include "reg_build_chan_list.h"
 #include <qdf_platform.h>
 #include <wlan_reg_services_api.h>
+#include <wlan_objmgr_vdev_obj.h>
 
 #define MAX_PWR_FCC_CHAN_12 8
 #define MAX_PWR_FCC_CHAN_13 2
@@ -448,36 +449,39 @@ static void reg_modify_chan_list_for_dfs_channels(
 #ifdef CONFIG_BAND_6GHZ
 #ifdef CONFIG_REG_CLIENT
 /**
- * reg_is_chan_connected() - Check if given channel is in connected
- *                           channel list
+ * reg_get_connected_chan_for_mode() - Get connected channel for given opmode
+ *                                     in given frequency range.
+ *
  * @pdev_priv_obj: Pdev privect object pointer
- * @chn_idx: Channel Index
+ * @device_mode: Device mode
+ * @start_freq: Start frequency
+ * @end_freq: End frequency
  *
- * Return: True if channel present in connected channel list else false
+ * Return: Channel info if channel in given range is connected for given
+ *         device mode
  */
-static bool
-reg_is_chan_connected(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
-		      uint16_t chn_idx)
+static struct wlan_channel *
+reg_get_connected_chan_for_mode(
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+		enum QDF_OPMODE device_mode, uint16_t start_freq,
+		uint16_t end_freq)
 {
-	qdf_freq_t freq;
 	struct wlan_objmgr_pdev *pdev;
 	struct wlan_objmgr_psoc *psoc;
 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
-	reg_is_chan_connected_callback callback = NULL;
-
-	freq = pdev_priv_obj->cur_chan_list[chn_idx].center_freq;
+	reg_get_connected_chan_for_mode_callback callback = NULL;
 
 	pdev = pdev_priv_obj->pdev_ptr;
 	if (!pdev) {
 		reg_err("pdev is NULL");
-		return QDF_STATUS_E_FAILURE;
+		return NULL;
 	}
 
 	psoc = wlan_pdev_get_psoc(pdev);
 	psoc_priv_obj = reg_get_psoc_obj(psoc);
 	if (!psoc_priv_obj) {
 		reg_err("reg psoc private obj is NULL");
-		return QDF_STATUS_E_FAILURE;
+		return NULL;
 	}
 
 	qdf_spin_lock_bh(&psoc_priv_obj->cbk_list_lock);
@@ -485,18 +489,92 @@ reg_is_chan_connected(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
 		callback = psoc_priv_obj->conn_chan_cb.cbk;
 	qdf_spin_unlock_bh(&psoc_priv_obj->cbk_list_lock);
 
-	if (callback) {
-		if (callback(psoc, QDF_STA_MODE, freq) ||
-		    callback(psoc, QDF_P2P_CLIENT_MODE, freq))
-			return true;
-	}
+	if (callback)
+		return callback(psoc, device_mode, start_freq, end_freq);
 
-	return false;
+	return NULL;
+}
+
+/**
+ * reg_get_active_6ghz_freq_range_with_fcc_set() - Get 6 GHz bonded channel
+ *                                                 range
+ * @pdev_priv_obj: Pointer to regulatory pdev privet object structure
+ * @bonded_chan: Pointer to bonded channel frequency structure
+ *
+ * Return: None.
+ */
+static void
+reg_get_active_6ghz_freq_range_with_fcc_set(
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+		struct bonded_channel_freq *bonded_chan)
+{
+	struct wlan_channel *conn_chan, *conn_chan_sta, *conn_chan_cli;
+	enum phy_ch_width max_width = CH_WIDTH_INVALID;
+	uint16_t start_freq_6g, end_freq_6g, conn_freq = 0;
+	const struct bonded_channel_freq *cur_bonded_chans;
+
+	start_freq_6g = pdev_priv_obj->cur_chan_list[MIN_6GHZ_CHANNEL].center_freq;
+	end_freq_6g = pdev_priv_obj->cur_chan_list[MAX_6GHZ_CHANNEL].center_freq;
+
+	conn_chan_sta = reg_get_connected_chan_for_mode(pdev_priv_obj,
+							QDF_STA_MODE,
+							start_freq_6g,
+							end_freq_6g);
+
+	conn_chan_cli = reg_get_connected_chan_for_mode(pdev_priv_obj,
+							QDF_P2P_CLIENT_MODE,
+							start_freq_6g,
+							end_freq_6g);
+
+	if (conn_chan_sta && conn_chan_cli)
+		max_width = QDF_MAX(conn_chan_sta->ch_width,
+				    conn_chan_cli->ch_width);
+	else if (conn_chan_sta)
+		max_width = conn_chan_sta->ch_width;
+	else if (conn_chan_cli)
+		max_width = conn_chan_cli->ch_width;
+
+	if (max_width < CH_WIDTH_INVALID) {
+		conn_chan = reg_get_connected_chan_for_mode(pdev_priv_obj,
+							    QDF_SAP_MODE,
+							    start_freq_6g,
+							    end_freq_6g);
+		if (conn_chan && max_width < conn_chan->ch_width)
+			max_width = conn_chan->ch_width;
+
+		conn_chan = reg_get_connected_chan_for_mode(pdev_priv_obj,
+							    QDF_P2P_GO_MODE,
+							    start_freq_6g,
+							    end_freq_6g);
+
+		if (conn_chan && max_width < conn_chan->ch_width)
+			max_width = conn_chan->ch_width;
+
+		if (conn_chan_sta)
+			conn_freq = conn_chan_sta->ch_freq;
+		else if (conn_chan_cli)
+			conn_freq = conn_chan_cli->ch_freq;
+
+		if (max_width == CH_WIDTH_20MHZ) {
+			bonded_chan->start_freq = conn_freq;
+			bonded_chan->end_freq = conn_freq;
+		} else {
+			cur_bonded_chans =  reg_get_bonded_chan_entry(
+								conn_freq,
+								max_width, 0);
+			if (cur_bonded_chans)
+				qdf_mem_copy(bonded_chan, cur_bonded_chans,
+					sizeof(struct bonded_channel_freq));
+		}
+	}
 }
+
 #else
-static inline bool
-reg_is_chan_connected(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
-		      uint16_t chn_idx)
+static inline struct wlan_channel *
+reg_get_connected_chan_for_mode(
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+		enum QDF_OPMODE device_mode, uint16_t start_freq,
+		uint16_t end_freq)
 {
 	return false;
 }
@@ -573,6 +651,9 @@ reg_dis_6g_chan_in_super_chan_list(struct wlan_objmgr_pdev *pdev,
 				   uint16_t chn_idx)
 {
 	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+	struct bonded_channel_freq *bonded_chan;
+	enum channel_enum active_6g_start = INVALID_CHANNEL;
+	enum channel_enum active_6g_end = INVALID_CHANNEL;
 
 	if (!pdev) {
 		reg_debug("pdev is NULL");
@@ -586,11 +667,30 @@ reg_dis_6g_chan_in_super_chan_list(struct wlan_objmgr_pdev *pdev,
 
 	pdev_priv_obj = reg_get_pdev_obj(pdev);
 
-	if (!reg_is_6ghz_band_set(pdev) &&
-	    !(reg_get_keep_6ghz_sta_cli_connection(pdev) &&
-	     reg_is_chan_connected(pdev_priv_obj,
-				   chn_idx + MIN_6GHZ_CHANNEL)))
-		reg_dis_chan_state_and_flags(
+	bonded_chan = qdf_mem_malloc(sizeof(struct bonded_channel_freq));
+	if (!bonded_chan)
+		return;
+
+	qdf_mem_zero(bonded_chan, sizeof(struct bonded_channel_freq));
+
+	if (reg_get_keep_6ghz_sta_cli_connection(pdev))
+		reg_get_active_6ghz_freq_range_with_fcc_set(pdev_priv_obj,
+							    bonded_chan);
+	if (bonded_chan->start_freq && bonded_chan->end_freq) {
+		active_6g_start = reg_get_chan_enum_for_freq(
+						bonded_chan->start_freq);
+		active_6g_end = reg_get_chan_enum_for_freq(
+						bonded_chan->end_freq);
+	}
+
+	qdf_mem_free(bonded_chan);
+
+	if (!reg_is_6ghz_band_set(pdev))
+		if (reg_is_chan_enum_invalid(active_6g_start) ||
+		    reg_is_chan_enum_invalid(active_6g_end) ||
+		    !(chn_idx >= active_6g_start &&
+		      chn_idx <= active_6g_end))
+			reg_dis_chan_state_and_flags(
 					&chan_info->state_arr[pwr_type],
 					&chan_info->chan_flags_arr[pwr_type]);
 }
@@ -730,41 +830,98 @@ static void reg_modify_chan_list_for_indoor_concurrency(
 #endif
 
 #ifdef CONFIG_BAND_6GHZ
+#ifdef CONFIG_REG_CLIENT
 /**
- * reg_modify_chan_list_for_band_6G() - Modify 6 GHz band channels
+ * reg_modify_inactive_6g_channels() - Modify inactive 6 GHz channels
  * @pdev_priv_obj: pointer to pdev privet object
  * @chan_list: pointer to channel list
  *
+ * For standalone STA or P2P client case keep all the bonded channels
+ * active and disable rest 6 GHz channels.
+ * For STA+SAP case or P2P cli+SAP case keep all the bonded channels
+ * active.
+ *
  * Return: None
  */
-static void reg_modify_chan_list_for_band_6G(
+static void reg_modify_inactive_6g_channels(
 		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
 		struct regulatory_channel *chan_list)
 {
 	enum channel_enum chan_enum;
-	struct wlan_objmgr_pdev *pdev;
-	bool keep_6ghz_sta_cli_conn;
+	struct bonded_channel_freq *bonded_chans;
+	enum channel_enum active_6g_start = INVALID_CHANNEL;
+	enum channel_enum active_6g_end = INVALID_CHANNEL;
 
-	pdev = pdev_priv_obj->pdev_ptr;
-	if (!pdev) {
-		reg_debug("pdev is NULL");
+	bonded_chans = qdf_mem_malloc(sizeof(struct bonded_channel_freq));
+	if (!bonded_chans)
 		return;
+
+	qdf_mem_zero(bonded_chans, sizeof(struct bonded_channel_freq));
+
+	reg_get_active_6ghz_freq_range_with_fcc_set(pdev_priv_obj,
+						    bonded_chans);
+
+	if (bonded_chans->start_freq && bonded_chans->end_freq) {
+		active_6g_start = reg_get_chan_enum_for_freq(
+						bonded_chans->start_freq);
+		active_6g_end = reg_get_chan_enum_for_freq(
+						bonded_chans->end_freq);
 	}
 
-	keep_6ghz_sta_cli_conn = reg_get_keep_6ghz_sta_cli_connection(pdev);
+	qdf_mem_free(bonded_chans);
 
 	reg_debug("disabling 6G");
 	for (chan_enum = MIN_6GHZ_CHANNEL;
 	     chan_enum <= MAX_6GHZ_CHANNEL; chan_enum++) {
-		if (keep_6ghz_sta_cli_conn &&
-		    reg_is_chan_connected(pdev_priv_obj,
-					  chan_enum))
+		if (!reg_is_chan_enum_invalid(active_6g_start) &&
+		    !reg_is_chan_enum_invalid(active_6g_end) &&
+		    (chan_enum >= active_6g_start &&
+		     chan_enum <= active_6g_end))
 			continue;
-		chan_list[chan_enum].chan_flags |=
-			REGULATORY_CHAN_DISABLED;
+
+		chan_list[chan_enum].chan_flags |= REGULATORY_CHAN_DISABLED;
 		chan_list[chan_enum].state = CHANNEL_STATE_DISABLE;
 	}
 }
+#else
+static inline void reg_modify_inactive_6g_channels(
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+		struct regulatory_channel *chan_list)
+{
+}
+#endif
+/**
+ * reg_modify_chan_list_for_band_6G() - Modify 6 GHz band channels
+ * @pdev_priv_obj: pointer to pdev privet object
+ * @chan_list: pointer to channel list
+ *
+ * Return: None
+ */
+static void reg_modify_chan_list_for_band_6G(
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+		struct regulatory_channel *chan_list)
+{
+	enum channel_enum chan_enum;
+	struct wlan_objmgr_pdev *pdev;
+
+	pdev = pdev_priv_obj->pdev_ptr;
+	if (!pdev) {
+		reg_debug("pdev is NULL");
+		return;
+	}
+
+	if (reg_get_keep_6ghz_sta_cli_connection(pdev)) {
+		reg_modify_inactive_6g_channels(pdev_priv_obj, chan_list);
+	} else {
+		reg_debug("disabling 6G");
+		for (chan_enum = MIN_6GHZ_CHANNEL;
+		     chan_enum <= MAX_6GHZ_CHANNEL; chan_enum++) {
+			chan_list[chan_enum].chan_flags |=
+				REGULATORY_CHAN_DISABLED;
+			chan_list[chan_enum].state = CHANNEL_STATE_DISABLE;
+		}
+	}
+}
 
 #ifdef CONFIG_REG_CLIENT
 /**

+ 2 - 2
umac/regulatory/core/src/reg_callbacks.c

@@ -480,7 +480,7 @@ void reg_unregister_ctry_change_callback(struct wlan_objmgr_psoc *psoc,
 
 void
 reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
-					reg_is_chan_connected_callback cbk)
+				reg_get_connected_chan_for_mode_callback cbk)
 {
 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
 
@@ -498,7 +498,7 @@ reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
 
 void
 reg_unregister_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
-					  reg_is_chan_connected_callback cbk)
+				reg_get_connected_chan_for_mode_callback cbk)
 {
 	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
 

+ 4 - 4
umac/regulatory/core/src/reg_callbacks.h

@@ -97,7 +97,7 @@ QDF_STATUS reg_send_scheduler_msg_nb(struct wlan_objmgr_psoc *psoc,
  */
 void
 reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
-					reg_is_chan_connected_callback cbk);
+			reg_get_connected_chan_for_mode_callback cbk);
 
 /**
  * reg_unregister_is_chan_connected_callback() - Unregister callback to check
@@ -109,7 +109,7 @@ reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
  */
 void
 reg_unregister_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
-					  reg_is_chan_connected_callback cbk);
+			reg_get_connected_chan_for_mode_callback cbk);
 
 #else
 static inline void reg_register_chan_change_callback(
@@ -147,13 +147,13 @@ static inline QDF_STATUS reg_send_scheduler_msg_nb(
 
 static inline void
 reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
-					reg_is_chan_connected_callback cbk)
+				reg_get_connected_chan_for_mode_callback cbk)
 {
 }
 
 static inline void
 reg_unregister_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
-					  reg_is_chan_connected_callback cbk)
+				reg_get_connected_chan_for_mode_callback cbk)
 {
 }
 #endif

+ 19 - 12
umac/regulatory/core/src/reg_priv_objs.h

@@ -100,23 +100,30 @@ struct ctry_change_cbk_entry {
 	reg_ctry_change_callback cbk;
 };
 
-/**
- * typedef reg_is_chan_connected_callback() - Regulatory callback to check if
- *                                            channel is connected
+/*
+ * typedef reg_get_connected_chan_for_mode_callback() - Regulatory callback to
+ * get connected channel in given range for specific opmode
  * @psoc: Pointer to psoc object
  * @opmode: vdev operating mode
- * @freq: Frequency
+ * @start_freq: Start frequency
+ * @end_freq: End frequency
+ *
+ * Return: Return connected channel information for the given power mode and
+ * frequency range
  */
-typedef bool (*reg_is_chan_connected_callback)(
-		struct wlan_objmgr_psoc *psoc,
-		enum QDF_OPMODE opmode,
-		uint32_t      freq);
+typedef struct wlan_channel * (*reg_get_connected_chan_for_mode_callback)(
+				struct wlan_objmgr_psoc *psoc,
+				enum QDF_OPMODE opmode,
+				qdf_freq_t start_freq,
+				qdf_freq_t end_freq);
 
-/* struct is_chan_connected_cbk_entry - Is channel connected callback entry
+/* struct get_connected_chan_for_mode_cbk_entry - Get connected channel for
+ * mode callback entry
+ *
  * @cbk: Callback
  */
-struct is_chan_connected_cbk_entry {
-	reg_is_chan_connected_callback cbk;
+struct get_connected_chan_for_mode_cbk_entry {
+	reg_get_connected_chan_for_mode_callback cbk;
 };
 
 #ifdef CONFIG_REG_CLIENT
@@ -256,7 +263,7 @@ struct wlan_regulatory_psoc_priv_obj {
 	bool user_ctry_priority;
 	bool user_ctry_set;
 	struct chan_change_cbk_entry cbk_list[REG_MAX_CHAN_CHANGE_CBKS];
-	struct is_chan_connected_cbk_entry conn_chan_cb;
+	struct get_connected_chan_for_mode_cbk_entry conn_chan_cb;
 	uint8_t num_chan_change_cbks;
 	struct ctry_change_cbk_entry cc_cbk;
 	uint8_t ch_avoid_ind;

+ 2 - 2
umac/regulatory/dispatcher/src/wlan_reg_services_api.c

@@ -1963,7 +1963,7 @@ wlan_reg_register_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
 					     void *cbk)
 {
 	reg_register_is_chan_connected_callback(psoc,
-					(reg_is_chan_connected_callback)cbk);
+				(reg_get_connected_chan_for_mode_callback)cbk);
 }
 
 void
@@ -1971,7 +1971,7 @@ wlan_reg_unregister_is_chan_connected_callback(struct wlan_objmgr_psoc *psoc,
 					       void *cbk)
 {
 	reg_unregister_is_chan_connected_callback(psoc,
-					(reg_is_chan_connected_callback)cbk);
+				(reg_get_connected_chan_for_mode_callback)cbk);
 }
 
 qdf_freq_t