summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbings <bings@codeaurora.org>2019-03-18 18:12:48 +0800
committernshrivas <nshrivas@codeaurora.org>2019-04-03 04:05:52 -0700
commit8a9c79dcb49572b84eab3b6f424c167b4e1c1ca6 (patch)
treedb9604cee0d4de6cb8b917fb19c109757cd9b27e
parentd1f98fc2b70ee805a573233cd3de3a2b2ef1f8bc (diff)
qcacld-3.0: Select valid channel after pcl selection fails
When SAP works in ACS mode, it needs to restart with a safe channel if current channel is unsafe. Sometimes no channel is selected from pcl channels. SAP can't just pick up one safe channel because the channel may be DFS channel while SAP may disable DFS master capability. SAP should select one valid channel for LTE COEX. Change-Id: I303165f82b5c2a8d06447df4ba23fdcba5b1083c CRs-Fixed: 2415007
-rw-r--r--core/cds/inc/cds_concurrency.h13
-rw-r--r--core/cds/inc/cds_reg_service.h4
-rw-r--r--core/cds/src/cds_concurrency.c327
-rw-r--r--core/hdd/src/wlan_hdd_main.c107
-rw-r--r--core/sap/inc/sap_api.h27
-rw-r--r--core/sap/src/sap_module.c149
6 files changed, 520 insertions, 107 deletions
diff --git a/core/cds/inc/cds_concurrency.h b/core/cds/inc/cds_concurrency.h
index 5d36f3e1e911..87e5deee66bf 100644
--- a/core/cds/inc/cds_concurrency.h
+++ b/core/cds/inc/cds_concurrency.h
@@ -917,6 +917,19 @@ QDF_STATUS cds_get_pcl_for_existing_conn(enum cds_con_mode mode,
uint8_t *pcl_ch, uint32_t *len,
uint8_t *weight_list, uint32_t weight_len,
bool all_matching_cxn_to_del);
+
+/**
+ * cds_get_valid_chans_from_range() - get valid channels from range
+ * @ch_list: pointer to channel list
+ * @ch_cnt: channel number of channel list
+ * @mode: device mode
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS cds_get_valid_chans_from_range(uint8_t *ch_list,
+ uint32_t *ch_cnt,
+ enum cds_con_mode mode);
+
QDF_STATUS cds_get_valid_chan_weights(struct sir_pcl_chan_weights *weight,
enum cds_con_mode mode);
QDF_STATUS cds_set_hw_mode_on_channel_switch(uint8_t session_id);
diff --git a/core/cds/inc/cds_reg_service.h b/core/cds/inc/cds_reg_service.h
index 22985ef5ff73..26d35c3928ed 100644
--- a/core/cds/inc/cds_reg_service.h
+++ b/core/cds/inc/cds_reg_service.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2019 The Linux Foundation. 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
@@ -37,6 +37,8 @@
#define CDS_CHANNEL_FREQ(chan_enum) chan_mapping[chan_enum].center_freq
#define CDS_IS_DFS_CH(chan_num) (cds_get_channel_state((chan_num)) == \
CHANNEL_STATE_DFS)
+#define CDS_IS_DISABLE_CH(chan_num) (cds_get_channel_state((chan_num)) == \
+ CHANNEL_STATE_DISABLE)
#define CDS_IS_PASSIVE_OR_DISABLE_CH(chan_num) \
(cds_get_channel_state(chan_num) != CHANNEL_STATE_ENABLE)
diff --git a/core/cds/src/cds_concurrency.c b/core/cds/src/cds_concurrency.c
index f9b3ccdb7122..ee5ab899f2b0 100644
--- a/core/cds/src/cds_concurrency.c
+++ b/core/cds/src/cds_concurrency.c
@@ -5693,6 +5693,295 @@ static bool cds_is_dbs_allowed_for_concurrency(
}
/**
+ * cds_skip_dfs_ch() - skip dfs channel or not
+ * @skip_dfs_channel: return check result
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS cds_skip_dfs_ch(bool *skip_dfs_channel)
+{
+ bool sta_sap_scc_on_dfs_chan;
+ struct cds_config_info *cds_cfg;
+
+ cds_cfg = cds_get_ini_config();
+ if (!cds_cfg) {
+ cds_err("cds config is NULL");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ *skip_dfs_channel = false;
+ if (!cds_cfg->dfs_master_enable) {
+ cds_debug("skip DFS ch for SAP/Go dfs master cap %d",
+ cds_cfg->dfs_master_enable);
+ *skip_dfs_channel = true;
+ }
+
+ if (!*skip_dfs_channel) {
+ sta_sap_scc_on_dfs_chan =
+ cds_is_sta_sap_scc_allowed_on_dfs_channel();
+ if (cds_mode_specific_connection_count(CDS_STA_MODE, NULL)
+ > 0 && !sta_sap_scc_on_dfs_chan) {
+ cds_debug("SAP/Go skips DFS ch if sta connects");
+ *skip_dfs_channel = true;
+ }
+ }
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * cds_modify_sap_pcl_based_on_dfs() - filter out DFS channel if needed
+ * @pcl_list_org: channel list to filter out
+ * @weight_list_org: weight of channel list
+ * @pcl_len_org: length of channel list
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS cds_modify_sap_pcl_based_on_dfs(uint8_t *pcl_list_org,
+ uint8_t *weight_list_org,
+ uint32_t *pcl_len_org)
+{
+ size_t i, pcl_len = 0;
+ bool skip_dfs_channel = false;
+ QDF_STATUS status;
+
+ if (*pcl_len_org > QDF_MAX_NUM_CHAN) {
+ cds_err("Invalid PCL List Length %d", *pcl_len_org);
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ status = cds_skip_dfs_ch(&skip_dfs_channel);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ cds_err("failed to get skip dfs ch info");
+ return status;
+ }
+
+ if (!skip_dfs_channel) {
+ cds_debug("No more operation on DFS channel");
+ return QDF_STATUS_SUCCESS;
+ }
+
+ for (i = 0; i < *pcl_len_org; i++) {
+ if (!CDS_IS_DFS_CH(pcl_list_org[i])) {
+ pcl_list_org[pcl_len] = pcl_list_org[i];
+ weight_list_org[pcl_len++] = weight_list_org[i];
+ }
+ }
+
+ *pcl_len_org = pcl_len;
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * cds_modify_sap_pcl_based_on_nol() - filter out nol channel
+ * @pcl_list_org: channel list to filter out
+ * @weight_list_org: weight of channel list
+ * @pcl_len_org: length of channel list
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS cds_modify_sap_pcl_based_on_nol(
+ uint8_t *pcl_list_org,
+ uint8_t *weight_list_org,
+ uint32_t *pcl_len_org)
+{
+ size_t i, pcl_len = 0;
+
+ if (*pcl_len_org > QDF_MAX_NUM_CHAN) {
+ cds_err("Invalid PCL List Length %d", *pcl_len_org);
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ for (i = 0; i < *pcl_len_org; i++) {
+ if (!CDS_IS_DISABLE_CH(pcl_list_org[i])) {
+ pcl_list_org[pcl_len] = pcl_list_org[i];
+ weight_list_org[pcl_len++] = weight_list_org[i];
+ }
+ }
+
+ *pcl_len_org = pcl_len;
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * cds_modify_sap_pcl_based_on_srd() - filter out srd channel if needed
+ * @pcl_list_org: pointer to channel list
+ * @weight_list_org: pointer to weight of channel list
+ * @pcl_len_org: pointer to length of channel list
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS cds_modify_sap_pcl_based_on_srd(
+ uint8_t *pcl_list_org,
+ uint8_t *weight_list_org,
+ uint32_t *pcl_len_org)
+{
+ size_t i, pcl_len = 0;
+ bool skip_srd_chan;
+ struct cds_config_info *cds_cfg;
+
+ cds_cfg = cds_get_ini_config();
+ if (!cds_cfg) {
+ cds_err("cds config is NULL");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ skip_srd_chan = !cds_cfg->etsi_srd_chan_in_master_mode &&
+ cds_is_5g_regdmn_etsi13();
+
+ if (!skip_srd_chan)
+ return QDF_STATUS_SUCCESS;
+
+ if (*pcl_len_org > QDF_MAX_NUM_CHAN) {
+ cds_err("Invalid PCL List Length %d", *pcl_len_org);
+ return QDF_STATUS_E_FAILURE;
+ }
+ for (i = 0; i < *pcl_len_org; i++) {
+ if (cds_is_etsi13_regdmn_srd_chan(cds_chan_to_freq(
+ pcl_list_org[i])))
+ continue;
+ pcl_list_org[pcl_len] = pcl_list_org[i];
+ weight_list_org[pcl_len++] = weight_list_org[i];
+ }
+
+ *pcl_len_org = pcl_len;
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * cds_pcl_modification_for_sap() - filter out channels for sap
+ * @pcl_channels: pointer to channel list
+ * @pcl_weight: pointer to weight of channel list
+ * @len: pointer to length of channel list
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS cds_pcl_modification_for_sap(
+ uint8_t *pcl_channels, uint8_t *pcl_weight,
+ uint32_t *len)
+{
+ QDF_STATUS status;
+ size_t i;
+
+ if (cds_is_sap_mandatory_channel_set()) {
+ status = cds_modify_sap_pcl_based_on_mandatory_channel(
+ pcl_channels, pcl_weight, len);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ cds_err("failed to get mandatory modified pcl for SAP");
+ return status;
+ }
+ cds_debug("mandatory modified pcl len:%d", *len);
+ for (i = 0; i < *len; i++)
+ cds_debug("chan:%d weight:%d",
+ pcl_channels[i], pcl_weight[i]);
+ }
+
+ status = cds_modify_sap_pcl_based_on_nol(
+ pcl_channels, pcl_weight, len);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ cds_err("failed to get nol modified pcl for SAP");
+ return status;
+ }
+ cds_debug("nol modified pcl len:%d", *len);
+ for (i = 0; i < *len; i++)
+ cds_debug("chan:%d weight:%d",
+ pcl_channels[i], pcl_weight[i]);
+
+ status = cds_modify_sap_pcl_based_on_dfs(
+ pcl_channels, pcl_weight, len);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ cds_err("failed to get dfs modified pcl for SAP");
+ return status;
+ }
+ cds_debug("dfs modified pcl len:%d", *len);
+ for (i = 0; i < *len; i++)
+ cds_debug("chan:%d weight:%d",
+ pcl_channels[i], pcl_weight[i]);
+
+ status = cds_modify_sap_pcl_based_on_srd(
+ pcl_channels, pcl_weight, len);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ cds_err("failed to get srd modified pcl for SAP");
+ return status;
+ }
+ cds_debug("modified final pcl len:%d", *len);
+ for (i = 0; i < *len; i++)
+ cds_debug("chan:%d weight:%d",
+ pcl_channels[i], pcl_weight[i]);
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * cds_pcl_modification_for_p2p_go() - filter out channels for go
+ * @pcl_channels: pointer to channel list
+ * @pcl_weight: pointer to weight of channel list
+ * @len: pointer to length of channel list
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS cds_pcl_modification_for_p2p_go(
+ uint8_t *pcl_channels, uint8_t *pcl_weight,
+ uint32_t *len)
+{
+ QDF_STATUS status;
+ size_t i;
+
+ status = cds_modify_pcl_based_on_enabled_channels(
+ pcl_channels, pcl_weight, len);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ cds_err("failed to get enabled channel modified pcl for GO");
+ return status;
+ }
+ cds_debug("enabled channel modified pcl len:%d", *len);
+ for (i = 0; i < *len; i++)
+ cds_debug("chan:%d weight:%d",
+ pcl_channels[i], pcl_weight[i]);
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * cds_mode_specific_modification_on_pcl() - filter out channel based on mode
+ * @pcl_channels: pointer to channel list
+ * @pcl_weight: pointer to weight of channel list
+ * @len: pointer to length of channel list
+ * @mode: device mode
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS cds_mode_specific_modification_on_pcl(
+ uint8_t *pcl_channels, uint8_t *pcl_weight,
+ uint32_t *len, enum cds_con_mode mode)
+{
+ QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+ switch (mode) {
+ case CDS_SAP_MODE:
+ status = cds_pcl_modification_for_sap(
+ pcl_channels, pcl_weight, len);
+ break;
+ case CDS_P2P_GO_MODE:
+ status = cds_pcl_modification_for_p2p_go(
+ pcl_channels, pcl_weight, len);
+ break;
+ case CDS_STA_MODE:
+ case CDS_P2P_CLIENT_MODE:
+ case CDS_IBSS_MODE:
+ status = QDF_STATUS_SUCCESS;
+ break;
+ default:
+ cds_err("unexpected mode %d", mode);
+ break;
+ }
+
+ return status;
+}
+
+/**
* cds_get_pcl() - provides the preferred channel list for
* new connection
* @mode: Device mode
@@ -10312,6 +10601,44 @@ bool cds_is_force_scc(void)
(hdd_ctx->config->WlanMccToSccSwitchMode ==
QDF_MCC_TO_SCC_WITH_PREFERRED_BAND));
}
+
+QDF_STATUS cds_get_valid_chans_from_range(
+ uint8_t *ch_list,
+ uint32_t *ch_cnt,
+ enum cds_con_mode mode)
+{
+ uint8_t ch_weight_list[QDF_MAX_NUM_CHAN];
+ uint32_t ch_weight_len;
+ QDF_STATUS status;
+ size_t chan_index = 0;
+
+ if (!ch_list || !ch_cnt) {
+ cds_err("Null parameters");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ for (chan_index = 0; chan_index < *ch_cnt; chan_index++)
+ ch_weight_list[chan_index] = WEIGHT_OF_GROUP1_PCL_CHANNELS;
+
+ ch_weight_len = *ch_cnt;
+
+ /* check the channel avoidance list for beaconing entities */
+ if (mode == CDS_SAP_MODE || mode == CDS_P2P_GO_MODE)
+ cds_update_with_safe_channel_list(ch_list, ch_cnt,
+ ch_weight_list,
+ ch_weight_len);
+
+ status = cds_mode_specific_modification_on_pcl(
+ ch_list, ch_weight_list, ch_cnt, mode);
+
+ if (QDF_IS_STATUS_ERROR(status)) {
+ cds_err("failed to get modified pcl for mode %d", mode);
+ return status;
+ }
+
+ return status;
+}
+
/**
* cds_get_valid_chan_weights() - Get the weightage for all
* requested valid channels
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index cebccf428f7c..eda121ceee7c 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -8070,111 +8070,6 @@ static void hdd_set_thermal_level_cb(void *context, u_int8_t level)
}
/**
- * hdd_get_safe_channel_from_pcl_and_acs_range() - Get safe channel for SAP
- * restart
- * @adapter: AP adapter, which should be checked for NULL
- *
- * Get a safe channel to restart SAP. PCL already takes into account the
- * unsafe channels. So, the PCL is validated with the ACS range to provide
- * a safe channel for the SAP to restart.
- *
- * Return: Channel number to restart SAP in case of success. In case of any
- * failure, the channel number returned is zero.
- */
-static uint8_t hdd_get_safe_channel_from_pcl_and_acs_range(
- hdd_adapter_t *adapter)
-{
- struct sir_pcl_list pcl;
- QDF_STATUS status;
- uint32_t i, j;
- tHalHandle *hal_handle;
- hdd_context_t *hdd_ctx;
- bool found = false;
-
- hdd_ctx = WLAN_HDD_GET_CTX(adapter);
- if (!hdd_ctx) {
- hdd_err("invalid HDD context");
- return INVALID_CHANNEL_ID;
- }
-
- hal_handle = WLAN_HDD_GET_HAL_CTX(adapter);
- if (!hal_handle) {
- hdd_err("invalid HAL handle");
- return INVALID_CHANNEL_ID;
- }
-
- status = cds_get_pcl_for_existing_conn(CDS_SAP_MODE,
- pcl.pcl_list, &pcl.pcl_len,
- pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list),
- false);
- if (QDF_IS_STATUS_ERROR(status)) {
- hdd_err("Get PCL failed");
- return INVALID_CHANNEL_ID;
- }
-
- /*
- * In some scenarios, like hw dbs disabled, sap+sap case, if operating
- * channel is unsafe channel, the pcl may be empty, instead of return,
- * try to choose a safe channel from acs range.
- */
- if (!pcl.pcl_len)
- hdd_debug("pcl length is zero!");
-
- hdd_debug("start:%d end:%d",
- adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch,
- adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch);
-
- /* PCL already takes unsafe channel into account */
- for (i = 0; i < pcl.pcl_len; i++) {
- hdd_debug("chan[%d]:%d", i, pcl.pcl_list[i]);
- if ((pcl.pcl_list[i] >=
- adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch) &&
- (pcl.pcl_list[i] <=
- adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch)) {
- hdd_debug("found PCL safe chan:%d", pcl.pcl_list[i]);
- return pcl.pcl_list[i];
- }
- }
-
- hdd_debug("no safe channel from PCL found in ACS range");
-
- /* Try for safe channel from all valid channel */
- pcl.pcl_len = MAX_NUM_CHAN;
- status = sme_get_cfg_valid_channels(hal_handle, pcl.pcl_list,
- &pcl.pcl_len);
- if (QDF_IS_STATUS_ERROR(status)) {
- hdd_err("error in getting valid channel list");
- return INVALID_CHANNEL_ID;
- }
-
- for (i = 0; i < pcl.pcl_len; i++) {
- hdd_debug("chan[%d]:%d", i, pcl.pcl_list[i]);
- found = false;
- for (j = 0; j < hdd_ctx->unsafe_channel_count; j++) {
- if (pcl.pcl_list[i] ==
- hdd_ctx->unsafe_channel_list[j]) {
- hdd_debug("unsafe chan:%d", pcl.pcl_list[i]);
- found = true;
- break;
- }
- }
-
- if (found)
- continue;
-
- if ((pcl.pcl_list[i] >=
- adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch) &&
- (pcl.pcl_list[i] <=
- adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch)) {
- hdd_debug("found safe chan:%d", pcl.pcl_list[i]);
- return pcl.pcl_list[i];
- }
- }
-
- return INVALID_CHANNEL_ID;
-}
-
-/**
* hdd_restart_sap() - Restarts SAP on the given channel
* @adapter: AP adapter
* @channel: Channel
@@ -8330,7 +8225,7 @@ void hdd_unsafe_channel_restart_sap(hdd_context_t *hdd_ctxt)
}
restart_chan =
- hdd_get_safe_channel_from_pcl_and_acs_range(
+ wlansap_get_safe_channel_from_pcl_and_acs_range(
adapter_temp);
if (!restart_chan) {
hdd_err("fail to restart SAP");
diff --git a/core/sap/inc/sap_api.h b/core/sap/inc/sap_api.h
index c27d9382f2c2..c82ab0a28f9e 100644
--- a/core/sap/inc/sap_api.h
+++ b/core/sap/inc/sap_api.h
@@ -1056,6 +1056,33 @@ void wlansap_set_stop_bss_inprogress(void *ctx, bool in_progress);
*/
bool wlansap_check_sap_started(void *sap_ctx);
+/**
+ * wlansap_filter_ch_based_acs() -filter out channel based on acs
+ * @sap_ctx: sap context
+ * @ch_list: pointer to channel list
+ * @ch_cnt: channel number of channel list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlansap_filter_ch_based_acs(void *sap_ctx,
+ uint8_t *ch_list,
+ uint32_t *ch_cnt);
+#if defined(FEATURE_WLAN_CH_AVOID)
+/**
+ * wlansap_get_safe_channel_from_pcl_and_acs_range() - Get safe channel for SAP
+ * restart
+ * @cds_ctx: sap context
+ *
+ * Get a safe channel to restart SAP. PCL already takes into account the
+ * unsafe channels. So, the PCL is validated with the ACS range to provide
+ * a safe channel for the SAP to restart.
+ *
+ * Return: Channel number to restart SAP in case of success. In case of any
+ * failure, the channel number returned is zero.
+ */
+uint8_t wlansap_get_safe_channel_from_pcl_and_acs_range(void *cds_ctx);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c
index 3721fad5e415..4ff040ec5930 100644
--- a/core/sap/src/sap_module.c
+++ b/core/sap/src/sap_module.c
@@ -3867,3 +3867,152 @@ bool wlansap_check_sap_started(void *sap_ctx)
return false;
}
+
+QDF_STATUS wlansap_filter_ch_based_acs(void *cds_ctx,
+ uint8_t *ch_list,
+ uint32_t *ch_cnt)
+{
+ size_t ch_index;
+ uint32_t target_ch_cnt = 0;
+ ptSapContext sap_ctx;
+
+ sap_ctx = CDS_GET_SAP_CB(cds_ctx);
+
+ if (!sap_ctx || !ch_list || !ch_cnt) {
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+ "Null parameters");
+ return QDF_STATUS_E_FAULT;
+ }
+
+ for (ch_index = 0; ch_index < *ch_cnt; ch_index++) {
+ if (ch_list[ch_index] >= sap_ctx->acs_cfg->start_ch &&
+ ch_list[ch_index] <= sap_ctx->acs_cfg->end_ch)
+ ch_list[target_ch_cnt++] = ch_list[ch_index];
+ }
+
+ *ch_cnt = target_ch_cnt;
+
+ return QDF_STATUS_SUCCESS;
+}
+
+#if defined(FEATURE_WLAN_CH_AVOID)
+/**
+ * wlansap_get_safe_channel() - Get safe channel from current regulatory
+ * @cds_ctx: sap context
+ *
+ * This function is used to get safe channel from current regulatory valid
+ * channels to restart SAP if failed to get safe channel from PCL.
+ *
+ * Return: Channel number to restart SAP in case of success. In case of any
+ * failure, the channel number returned is zero.
+ */
+static uint8_t
+wlansap_get_safe_channel(void *cds_ctx)
+{
+ struct sir_pcl_list pcl;
+ QDF_STATUS status;
+ ptSapContext sap_ctx;
+
+ sap_ctx = CDS_GET_SAP_CB(cds_ctx);
+
+ if (!sap_ctx) {
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+ "Invalid sap_ctx %pK",
+ sap_ctx);
+ return INVALID_CHANNEL_ID;
+ }
+
+ status = cds_get_valid_chans(pcl.pcl_list,
+ &pcl.pcl_len);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+ "error %d in getting valid channel list", status);
+ return INVALID_CHANNEL_ID;
+ }
+
+ status = wlansap_filter_ch_based_acs(cds_ctx,
+ pcl.pcl_list,
+ &pcl.pcl_len);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+ "failed to filter ch from acs %d", status);
+ return INVALID_CHANNEL_ID;
+ }
+
+ if (pcl.pcl_len) {
+ status = cds_get_valid_chans_from_range(pcl.pcl_list,
+ &pcl.pcl_len,
+ CDS_SAP_MODE);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+ "failed to get valid channel: %d", status);
+ return INVALID_CHANNEL_ID;
+ }
+
+ if (pcl.pcl_len) {
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
+ "select %d from valid channel list",
+ pcl.pcl_list[0]);
+ return pcl.pcl_list[0];
+ }
+ }
+
+ return INVALID_CHANNEL_ID;
+}
+
+uint8_t wlansap_get_safe_channel_from_pcl_and_acs_range(void *cds_ctx)
+{
+ struct sir_pcl_list pcl;
+ QDF_STATUS status;
+ ptSapContext sap_ctx;
+
+ sap_ctx = CDS_GET_SAP_CB(cds_ctx);
+
+ if (!sap_ctx) {
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+ "Invalid sap_ctx %pK",
+ sap_ctx);
+ return INVALID_CHANNEL_ID;
+ }
+
+ status = cds_get_pcl_for_existing_conn(
+ CDS_SAP_MODE, pcl.pcl_list, &pcl.pcl_len,
+ pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list),
+ false);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+ "Get PCL failed");
+ return INVALID_CHANNEL_ID;
+ }
+
+ if (pcl.pcl_len) {
+ status = wlansap_filter_ch_based_acs(cds_ctx,
+ pcl.pcl_list,
+ &pcl.pcl_len);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
+ "failed to filter ch from acs %d", status);
+ return INVALID_CHANNEL_ID;
+ }
+
+ if (pcl.pcl_len) {
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
+ "select %d from valid channel list",
+ pcl.pcl_list[0]);
+ return pcl.pcl_list[0];
+ }
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
+ "no safe channel from PCL found in ACS range");
+ } else {
+ QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
+ "pcl length is zero!");
+ }
+
+ /*
+ * In some scenarios, like hw dbs disabled, sap+sap case, if operating
+ * channel is unsafe channel, the pcl may be empty, instead of return,
+ * try to choose a safe channel from acs range.
+ */
+ return wlansap_get_safe_channel(cds_ctx);
+}
+#endif