From 1b3be2948ec329aaa67bae6f674dd47d348bdf4a Mon Sep 17 00:00:00 2001 From: Huashan Qu Date: Tue, 24 Dec 2019 11:04:18 +0800 Subject: [PATCH] qcacld-3.0: dynamic channel switch implementation When dynamic channel switch is enabled, trigger acs and switch to best channel if wlan interference is found in 5g mac. Change-Id: I56661f5c42a233a0dc0a6400d75cb8f5c0019706 CRs-Fixed: 2599176 --- .../policy_mgr/inc/wlan_policy_mgr_api.h | 31 ++- .../src/wlan_policy_mgr_get_set_utils.c | 73 ++++++- core/hdd/src/wlan_hdd_cfg80211.c | 10 +- core/hdd/src/wlan_hdd_dcs.c | 187 ++++++++++++++++++ core/hdd/src/wlan_hdd_dcs.h | 81 ++++++++ core/hdd/src/wlan_hdd_hostapd.c | 41 +++- core/hdd/src/wlan_hdd_main.c | 3 + core/sap/inc/sap_api.h | 137 +++++++++++++ core/sap/src/sap_api_link_cntl.c | 6 +- core/sap/src/sap_fsm.c | 15 +- core/sap/src/sap_internal.h | 4 + core/sap/src/sap_module.c | 152 +++++++++++++- core/wma/src/wma_dev_if.c | 89 ++++++++- 13 files changed, 809 insertions(+), 20 deletions(-) create mode 100644 core/hdd/src/wlan_hdd_dcs.c create mode 100644 core/hdd/src/wlan_hdd_dcs.h diff --git a/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h b/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h index 50851d656259..3f1bf2640301 100644 --- a/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h +++ b/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h @@ -72,6 +72,7 @@ typedef const enum policy_mgr_conc_next_action * @CSA_REASON_LTE_COEX: LTE coex. * @CSA_REASON_CONCURRENT_NAN_EVENT: NAN concurrency. * @CSA_REASON_BAND_RESTRICTED: band disabled or re-enabled + * @CSA_REASON_DCS: DCS * */ enum sap_csa_reason_code { @@ -84,7 +85,8 @@ enum sap_csa_reason_code { CSA_REASON_UNSAFE_CHANNEL, CSA_REASON_LTE_COEX, CSA_REASON_CONCURRENT_NAN_EVENT, - CSA_REASON_BAND_RESTRICTED + CSA_REASON_BAND_RESTRICTED, + CSA_REASON_DCS, }; /** @@ -1878,6 +1880,33 @@ QDF_STATUS policy_mgr_get_chan_by_session_id(struct wlan_objmgr_psoc *psoc, uint8_t session_id, uint32_t *ch_freq); +/** + * policy_mgr_get_sap_go_count_on_mac() - Provide the count of sap and go on + * given mac + * @psoc: PSOC object information + * @list: To provide the vdev_id of the satisfied sap and go (optional) + * @mac_id: MAC ID + * + * This function provides the count of the matched sap and go + * + * Return: count of the satisfied sap and go + */ +uint32_t policy_mgr_get_sap_go_count_on_mac(struct wlan_objmgr_psoc *psoc, + uint32_t *list, uint8_t mac_id); + +/** + * policy_mgr_is_sta_gc_active_on_mac() - Is there active sta/gc for a + * given mac id + * @psoc: PSOC object information + * @mac_id: MAC ID + * + * Checks if there is active sta/gc for a given mac id + * + * Return: true if there is active sta/gc for a given mac id, false otherwise + */ +bool policy_mgr_is_sta_gc_active_on_mac(struct wlan_objmgr_psoc *psoc, + uint8_t mac_id); + /** * policy_mgr_get_mac_id_by_session_id() - Get MAC ID for a given session ID * @psoc: PSOC object information diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c index ca8d0df64f5d..d78dead8cf3c 100644 --- a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c +++ b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c @@ -2564,7 +2564,8 @@ policy_mgr_allow_concurrency_csa(struct wlan_objmgr_psoc *psoc, */ qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); - if (forced && reason == CSA_REASON_UNSAFE_CHANNEL) + if (forced && (reason == CSA_REASON_UNSAFE_CHANNEL || + reason == CSA_REASON_DCS)) policy_mgr_store_and_del_conn_info_by_chan_and_mode( psoc, old_ch_freq, mode, info, &num_cxn_del); else @@ -3065,6 +3066,44 @@ bool policy_mgr_is_multiple_active_sta_sessions(struct wlan_objmgr_psoc *psoc) psoc, PM_STA_MODE, NULL) > 1; } +bool policy_mgr_is_sta_gc_active_on_mac(struct wlan_objmgr_psoc *psoc, + uint8_t mac_id) +{ + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t index, count; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + count = policy_mgr_mode_specific_connection_count( + psoc, PM_STA_MODE, list); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (index = 0; index < count; index++) { + if (mac_id == pm_conc_connection_list[list[index]].mac) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return true; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + count = policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_CLIENT_MODE, list); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (index = 0; index < count; index++) { + if (mac_id == pm_conc_connection_list[list[index]].mac) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return true; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return false; +} + /** * policy_mgr_is_sta_active_connection_exists() - Check if a STA * connection is active @@ -3361,6 +3400,38 @@ QDF_STATUS policy_mgr_get_mac_id_by_session_id(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_E_FAILURE; } +uint32_t policy_mgr_get_sap_go_count_on_mac(struct wlan_objmgr_psoc *psoc, + uint32_t *list, uint8_t mac_id) +{ + uint32_t conn_index; + uint32_t count = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return count; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].mac == mac_id && + pm_conc_connection_list[conn_index].in_use && + (pm_conc_connection_list[conn_index].mode == PM_SAP_MODE || + pm_conc_connection_list[conn_index].mode == + PM_P2P_GO_MODE)) { + if (list) + list[count] = + pm_conc_connection_list[conn_index].vdev_id; + count++; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return count; +} + QDF_STATUS policy_mgr_get_mcc_session_id_on_mac(struct wlan_objmgr_psoc *psoc, uint8_t mac_id, uint8_t session_id, uint8_t *mcc_session_id) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 894059ef1314..80bf2eb1c32f 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -1950,6 +1950,9 @@ int wlan_hdd_cfg80211_start_acs(struct hdd_adapter *adapter) if (status > 0) { /*notify hostapd about channel override */ wlan_hdd_cfg80211_acs_ch_select_evt(adapter); + wlansap_dcs_set_wlan_interference_mitigation_on_band( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + sap_config); return 0; } } @@ -2001,6 +2004,8 @@ int wlan_hdd_cfg80211_start_acs(struct hdd_adapter *adapter) if (sap_is_auto_channel_select(WLAN_HDD_GET_SAP_CTX_PTR(adapter))) sap_config->acs_cfg.acs_mode = true; + qdf_atomic_set(&adapter->session.ap.acs_in_progress, 1); + return 0; } @@ -3141,6 +3146,9 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, sap_config->acs_cfg.vht_seg1_center_ch_freq; /*notify hostapd about channel override */ wlan_hdd_cfg80211_acs_ch_select_evt(adapter); + wlansap_dcs_set_wlan_interference_mitigation_on_band( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + sap_config); ret = 0; goto out; } @@ -3358,7 +3366,7 @@ static int hdd_get_acs_evt_data_len(void) * @pri_channel: SAP ACS procedure selected Primary channel * @sec_channel: SAP ACS procedure selected secondary channel * - * This is a callback function from SAP module on ACS procedure is completed. + * This is a callback function on ACS procedure is completed. * This function send the ACS selected channel information to hostapd * * Return: None diff --git a/core/hdd/src/wlan_hdd_dcs.c b/core/hdd/src/wlan_hdd_dcs.c new file mode 100644 index 000000000000..e6160d0bcf73 --- /dev/null +++ b/core/hdd/src/wlan_hdd_dcs.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2020, 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 above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_dcs.c + * + * DCS implementation. + * + */ + +#include +#include +#include +#include +/** + * hdd_dcs_cb() - hdd dcs specific callback + * @psoc: psoc + * @mac_id: mac_id + * @interference_type: wlan or continuous wave interference type + * @arg: List of arguments + * + * This callback is registered with dcs component to start acs operation + * + * Return: None + */ +static void hdd_dcs_cb(struct wlan_objmgr_psoc *psoc, uint8_t mac_id, + uint8_t interference_type, void *arg) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)arg; + struct hdd_adapter *adapter; + uint32_t count; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t index; + + /* + * so far CAP_DCS_CWIM interference mitigation is not supported + */ + if (interference_type == CAP_DCS_CWIM) { + hdd_debug("CW interference mitigation is not supported"); + return; + } + + if (policy_mgr_is_force_scc(psoc) && + policy_mgr_is_sta_gc_active_on_mac(psoc, mac_id)) { + hdd_debug("force scc %d, mac id %d sta gc count %d", + policy_mgr_is_force_scc(psoc), mac_id, + policy_mgr_is_sta_gc_active_on_mac(psoc, mac_id)); + return; + } + + count = policy_mgr_get_sap_go_count_on_mac(psoc, list, mac_id); + for (index = 0; index < count; index++) { + adapter = hdd_get_adapter_by_vdev(hdd_ctx, list[index]); + if (wlansap_dcs_is_wlan_interference_mitigation_enabled( + WLAN_HDD_GET_SAP_CTX_PTR(adapter))) { + hdd_debug("DCS triggers ACS on vdev_id=%u, mac_id=%u", + list[index], mac_id); + wlan_hdd_cfg80211_start_acs(adapter); + return; + } + } +} + +void hdd_dcs_register_cb(struct hdd_context *hdd_ctx) +{ + ucfg_dcs_register_cb(hdd_ctx->psoc, hdd_dcs_cb, hdd_ctx); +} + +void hdd_dcs_hostapd_set_chan(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + qdf_freq_t dcs_ch_freq) +{ + QDF_STATUS status; + uint8_t mac_id; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t conn_index, count; + struct hdd_adapter *adapter; + uint32_t dcs_ch = wlan_reg_freq_to_chan(hdd_ctx->pdev, dcs_ch_freq); + + status = policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc, vdev_id, + &mac_id); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("get mac id failed"); + return; + } + count = policy_mgr_get_sap_go_count_on_mac(hdd_ctx->psoc, list, mac_id); + + /* + * Dcs can only be enabled after all vdev finish csa. + * Set vdev starting for every vdev before doing csa. + * The CSA triggered by DCS will be done in serial. + */ + for (conn_index = 0; conn_index < count; conn_index++) { + adapter = hdd_get_adapter_by_vdev(hdd_ctx, list[conn_index]); + + if (adapter->session.ap.operating_chan_freq != dcs_ch_freq) + wlansap_dcs_set_vdev_starting( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), true); + else + wlansap_dcs_set_vdev_starting( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), false); + } + for (conn_index = 0; conn_index < count; conn_index++) { + adapter = hdd_get_adapter_by_vdev(hdd_ctx, list[conn_index]); + + if (adapter->session.ap.operating_chan_freq != dcs_ch_freq) { + hdd_ctx->acs_policy.acs_chan_freq = AUTO_CHANNEL_SELECT; + hdd_debug("dcs triggers old ch:%d new ch:%d", + adapter->session.ap.operating_chan_freq, + dcs_ch_freq); + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, + adapter->vdev_id, + CSA_REASON_DCS); + hdd_switch_sap_channel(adapter, dcs_ch, true); + + return; + } + } +} + +/** + * hdd_dcs_hostapd_enable_wlan_interference_mitigation() - enable wlan + * interference mitigation + * @hdd_ctx: hdd ctx + * @vdev_id: vdev id + * + * This function is used to enable wlan interference mitigation through + * send dcs command. + * + * Return: None + */ +static void hdd_dcs_hostapd_enable_wlan_interference_mitigation( + struct hdd_context *hdd_ctx, + uint8_t vdev_id) +{ + QDF_STATUS status; + uint8_t mac_id; + struct hdd_adapter *adapter; + + status = policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc, vdev_id, + &mac_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("get mac id failed"); + return; + } + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + + if (wlansap_dcs_is_wlan_interference_mitigation_enabled( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)) && + wlan_reg_is_5ghz_ch_freq(adapter->session.ap.operating_chan_freq)) + ucfg_config_dcs_enable(hdd_ctx->psoc, mac_id, CAP_DCS_WLANIM); + ucfg_wlan_dcs_cmd(hdd_ctx->psoc, mac_id, true); +} + +void hdd_dcs_chan_select_complete(struct hdd_adapter *adapter) +{ + qdf_freq_t dcs_freq; + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("Invalid HDD context pointer"); + return; + } + + dcs_freq = wlansap_dcs_get_freq(WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + if (dcs_freq && dcs_freq != adapter->session.ap.operating_chan_freq) + hdd_dcs_hostapd_set_chan(hdd_ctx, adapter->vdev_id, dcs_freq); + else + hdd_dcs_hostapd_enable_wlan_interference_mitigation( + hdd_ctx, + adapter->vdev_id); +} diff --git a/core/hdd/src/wlan_hdd_dcs.h b/core/hdd/src/wlan_hdd_dcs.h new file mode 100644 index 000000000000..59741dd256cf --- /dev/null +++ b/core/hdd/src/wlan_hdd_dcs.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020, 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 above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_dcs.h + * + * WLAN Host Device Driver dcs related implementation + * + */ + +#if !defined(WLAN_HDD_DCS_H) +#define WLAN_HDD_DCS_H + +#include + +#ifdef DCS_INTERFERENCE_DETECTION +/** + * hdd_dcs_register_cb() - register dcs callback + * @hdd_ctx: hdd ctx + * + * This function is used to register the HDD callbacks with dcs component + * + * Return: None + */ +void hdd_dcs_register_cb(struct hdd_context *hdd_ctx); + +/** + * hdd_dcs_hostapd_set_chan() - switch sap channel to dcs channel + * @hdd_ctx: hdd ctx + * @vdev_id: vdev id + * @dcs_ch_freq: dcs channel freq + * + * This function is used to switch sap channel to dcs channel using (E)CSA + * + * Return: None + */ +void hdd_dcs_hostapd_set_chan(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + qdf_freq_t dcs_ch_freq); + +/** + * hdd_dcs_chan_select_complete() - dcs triggered channel select + * complete handling + * @adapter: hdd adapter pointer + * + * When dcs triggered channel select complete, this function is used to do + * switch sap to new dcs channel or just to enable interference mitigation + * + * Return: None + */ +void hdd_dcs_chan_select_complete(struct hdd_adapter *adapter); +#else +static inline void hdd_dcs_register_cb(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_dcs_hostapd_set_chan(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + qdf_freq_t dcs_ch_freq) +{ +} + +static inline void hdd_dcs_chan_select_complete(struct hdd_adapter *adapter) +{ +} +#endif + +#endif /* end #if !defined(WLAN_HDD_DCS_H) */ diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 4e263b68fc3d..59533b63020d 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -93,6 +93,7 @@ #include #include "wlan_hdd_sta_info.h" #include "ftm_time_sync_ucfg_api.h" +#include #define ACS_SCAN_EXPIRY_TIMEOUT_S 4 @@ -2586,7 +2587,15 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event, ap_ctx->sap_config.acs_cfg.pri_ch_freq, ap_ctx->sap_config.acs_cfg.ch_width); - wlan_hdd_cfg80211_acs_ch_select_evt(adapter); + if (qdf_atomic_read(&adapter->session.ap.acs_in_progress) && + test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + hdd_dcs_chan_select_complete(adapter); + } else { + wlan_hdd_cfg80211_acs_ch_select_evt(adapter); + wlansap_dcs_set_wlan_interference_mitigation_on_band( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + &ap_ctx->sap_config); + } return QDF_STATUS_SUCCESS; case eSAP_ECSA_CHANGE_CHAN_IND: @@ -2630,6 +2639,11 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event, if (ap_ctx->sap_context->csa_reason == CSA_REASON_UNSAFE_CHANNEL) hdd_unsafe_channel_restart_sap(hdd_ctx); + else if (ap_ctx->sap_context->csa_reason == CSA_REASON_DCS) + hdd_dcs_hostapd_set_chan( + hdd_ctx, adapter->vdev_id, + adapter->session.ap.operating_chan_freq); + return QDF_STATUS_SUCCESS; default: @@ -2883,6 +2897,7 @@ int hdd_softap_set_channel_change(struct net_device *dev, int target_chan_freq, uint8_t scc_on_lte_coex = 0; bool is_p2p_go_session = false; struct wlan_objmgr_vdev *vdev; + bool strict; hdd_ctx = WLAN_HDD_GET_CTX(adapter); ret = wlan_hdd_validate_context(hdd_ctx); @@ -3004,11 +3019,20 @@ int hdd_softap_set_channel_change(struct net_device *dev, int target_chan_freq, is_p2p_go_session = true; hdd_objmgr_put_vdev(vdev); + strict = is_p2p_go_session; + /* + * scc_on_lte_coex should be considered only when csa is triggered + * by unsafe channel. + */ + if (sap_ctx->csa_reason == CSA_REASON_UNSAFE_CHANNEL) + strict = strict || (forced && !scc_on_lte_coex); + else + strict = strict || forced; status = wlansap_set_channel_change_with_csa( WLAN_HDD_GET_SAP_CTX_PTR(adapter), target_chan_freq, target_bw, - (forced && !scc_on_lte_coex) || is_p2p_go_session); + strict); if (QDF_STATUS_SUCCESS != status) { hdd_err("SAP set channel failed for channel freq: %d, bw: %d", @@ -3372,7 +3396,7 @@ QDF_STATUS hdd_init_ap_mode(struct hdd_adapter *adapter, bool reinit) struct hdd_hostapd_state *phostapdBuf; struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); QDF_STATUS status = QDF_STATUS_E_FAILURE; - struct sap_context *sap_context = NULL; + struct sap_context *sap_ctx; int ret; enum dfs_mode acs_dfs_mode; bool acs_with_more_param = 0; @@ -3384,8 +3408,8 @@ QDF_STATUS hdd_init_ap_mode(struct hdd_adapter *adapter, bool reinit) hdd_debug("SSR in progress: %d", reinit); qdf_atomic_init(&adapter->session.ap.acs_in_progress); - sap_context = hdd_hostapd_init_sap_session(adapter, reinit); - if (!sap_context) { + sap_ctx = hdd_hostapd_init_sap_session(adapter, reinit); + if (!sap_ctx) { hdd_err("Invalid sap_ctx"); goto error_release_vdev; } @@ -3474,6 +3498,9 @@ QDF_STATUS hdd_init_ap_mode(struct hdd_adapter *adapter, bool reinit) if (!reinit) { adapter->session.ap.sap_config.acs_cfg.acs_mode = false; + wlansap_dcs_set_vdev_wlan_interference_mitigation(sap_ctx, + false); + wlansap_dcs_set_vdev_starting(sap_ctx, false); qdf_mem_zero(&adapter->session.ap.sap_config.acs_cfg, sizeof(struct sap_acs_cfg)); } @@ -5746,6 +5773,7 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, tSirUpdateIE update_ie; int ret; mac_handle_t mac_handle; + struct sap_context *sap_ctx; hdd_enter(); @@ -5811,6 +5839,9 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, cds_flush_work(&adapter->sap_stop_bss_work); adapter->session.ap.sap_config.acs_cfg.acs_mode = false; + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter); + wlansap_dcs_set_vdev_wlan_interference_mitigation(sap_ctx, false); + wlansap_dcs_set_vdev_starting(sap_ctx, false); qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0); hdd_debug("Disabling queues"); wlan_hdd_netif_queue_control(adapter, diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 48b15ca6fbfc..0559a6c54957 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -180,6 +180,7 @@ #include #include "cfg_nan_api.h" #include "wlan_hdd_btc_chain_mode.h" +#include #ifdef MODULE #define WLAN_MODULE_NAME module_name(THIS_MODULE) @@ -342,6 +343,7 @@ static const struct category_info cinfo[MAX_SUPPORTED_CATEGORY] = { [QDF_MODULE_ID_CMN_MLME] = {QDF_TRACE_LEVEL_ALL}, [QDF_MODULE_ID_NAN] = {QDF_TRACE_LEVEL_ALL}, [QDF_MODULE_ID_CP_STATS] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_DCS] = {QDF_TRACE_LEVEL_ALL}, [QDF_MODULE_ID_INTEROP_ISSUES_AP] = {QDF_TRACE_LEVEL_ALL}, [QDF_MODULE_ID_BLACKLIST_MGR] = {QDF_TRACE_LEVEL_ALL}, [QDF_MODULE_ID_DIRECT_BUF_RX] = {QDF_TRACE_LEVEL_ALL}, @@ -13396,6 +13398,7 @@ int hdd_register_cb(struct hdd_context *hdd_ctx) hdd_lost_link_info_cb); wlan_hdd_register_cp_stats_cb(hdd_ctx); + hdd_dcs_register_cb(hdd_ctx); /* print error and not block the startup process */ if (!QDF_IS_STATUS_SUCCESS(status)) diff --git a/core/sap/inc/sap_api.h b/core/sap/inc/sap_api.h index dab93afa3ef0..1e3d20e25687 100644 --- a/core/sap/inc/sap_api.h +++ b/core/sap/inc/sap_api.h @@ -619,6 +619,19 @@ typedef struct sSapDfsInfo { uint16_t reduced_beacon_interval; } tSapDfsInfo; +#ifdef DCS_INTERFERENCE_DETECTION +/** + * struct sap_dcs_info - record sap dcs information. + * @wlan_interference_mitigation_enable: wlan interference mitigation + * is enabled per vdev. + * @is_vdev_starting: is vdev doing restart because of dcs. + */ +struct sap_dcs_info { + bool wlan_interference_mitigation_enable[WLAN_MAX_VDEVS]; + bool is_vdev_starting[WLAN_MAX_VDEVS]; +}; +#endif + struct sap_ctx_list { void *sap_context; enum QDF_OPMODE sapPersona; @@ -633,6 +646,9 @@ typedef struct tagSapStruct { #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ bool acs_with_more_param; bool enable_dfs_phy_error_logs; +#ifdef DCS_INTERFERENCE_DETECTION + struct sap_dcs_info dcs_info; +#endif } tSapStruct, *tpSapStruct; /** @@ -1469,6 +1485,127 @@ wlansap_get_safe_channel_from_pcl_and_acs_range(struct sap_context *sap_ctx); */ qdf_freq_t wlansap_get_chan_band_restrict(struct sap_context *sap_ctx); +#ifdef DCS_INTERFERENCE_DETECTION +/** + * wlansap_dcs_set_vdev_wlan_interference_mitigation() - set wlan + * interference mitigation enable information per vdev + * @sap_context: sap context + * @wlan_interference_mitigation_enable: wlan interference mitigation + * enable or not + * + * This function is used to set whether wlan interference mitigation + * enable or not + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_dcs_set_vdev_wlan_interference_mitigation( + struct sap_context *sap_context, + bool wlan_interference_mitigation_enable); + +/** + * wlansap_dcs_set_wlan_interference_mitigation_on_band() - set wlan + * interference mitigation enable information based on band information + * @sap_context: sap context + * @sap_cfg: sap config + * + * This function is used to set whether wlan interference mitigation + * enable or not based on band information + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_dcs_set_wlan_interference_mitigation_on_band( + struct sap_context *sap_context, + struct sap_config *sap_cfg); + +/** + * wlansap_dcs_set_vdev_starting() - set vdev starting + * @sap_context: sap context + * @vdev_starting: vdev in starting states + * + * This function is used to set whether vdev starting or not + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_dcs_set_vdev_starting(struct sap_context *sap_context, + bool vdev_starting); + +/** + * wlansap_dcs_is_wlan_interference_mitigation_enabled() - get wlan interference + * mitigation enabled information + * @sap_context: sap context + * + * This function is used to get wlan interference mitigation enabled information + * with given sap + * + * Return: true if wlan interference mitigation is enabled with given sap + */ +bool wlansap_dcs_is_wlan_interference_mitigation_enabled( + struct sap_context *sap_context); + +/** + * wlansap_dcs_get_freq() - get dcs channel frequency + * @sap_context: sap context + * + * This function is used to get dcs channel frequency with give sap + * + * Return: sap dcs channel frequency + */ +qdf_freq_t wlansap_dcs_get_freq(struct sap_context *sap_context); +#else +static inline QDF_STATUS wlansap_dcs_set_vdev_wlan_interference_mitigation( + struct sap_context *sap_context, + bool wlan_interference_mitigation_enable) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wlansap_dcs_set_wlan_interference_mitigation_on_band( + struct sap_context *sap_context, + struct sap_config *sap_cfg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wlansap_dcs_set_vdev_starting( + struct sap_context *sap_context, bool vdev_starting) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool wlansap_dcs_is_wlan_interference_mitigation_enabled( + struct sap_context *sap_context) +{ + return false; +} + +static inline qdf_freq_t wlansap_dcs_get_freq(struct sap_context *sap_context) +{ + return 0; +} +#endif + +/** + * wlansap_dump_acs_ch_freq() - print acs channel frequency + * @sap_ctx: sap context + * + * This function is used to print acs channel frequecny + * + * Return: None + */ +void wlansap_dump_acs_ch_freq(struct sap_context *sap_context); + +/** + * wlansap_set_acs_ch_freq() - set acs channel frequency + * @sap_ctx: sap context + * @ch_freq: ch_freq to be set + * + * This function is used to set acs channel frequency + * + * Return: None + */ +void wlansap_set_acs_ch_freq(struct sap_context *sap_context, + qdf_freq_t ch_freq); + /** * sap_acquire_vdev_ref() - Increment reference count for vdev object * @psoc: Object Manager PSoC object diff --git a/core/sap/src/sap_api_link_cntl.c b/core/sap/src/sap_api_link_cntl.c index 3670e686284c..f04a09759fe3 100644 --- a/core/sap/src/sap_api_link_cntl.c +++ b/core/sap/src/sap_api_link_cntl.c @@ -334,7 +334,7 @@ QDF_STATUS wlansap_pre_start_bss_acs_scan_callback(mac_handle_t mac_handle, scan_status); oper_channel = sap_select_default_oper_chan(sap_ctx->acs_cfg); - sap_ctx->chan_freq = oper_channel; + wlansap_set_acs_ch_freq(sap_ctx, oper_channel); sap_ctx->acs_cfg->pri_ch_freq = oper_channel; sap_config_acs_result(mac_handle, sap_ctx, sap_ctx->acs_cfg->ht_sec_ch_freq); @@ -354,11 +354,13 @@ QDF_STATUS wlansap_pre_start_bss_acs_scan_callback(mac_handle_t mac_handle, oper_channel = sap_select_default_oper_chan(sap_ctx->acs_cfg); } - sap_ctx->chan_freq = oper_channel; + wlansap_set_acs_ch_freq(sap_ctx, oper_channel); sap_ctx->acs_cfg->pri_ch_freq = oper_channel; sap_config_acs_result(mac_handle, sap_ctx, sap_ctx->acs_cfg->ht_sec_ch_freq); + wlansap_dump_acs_ch_freq(sap_ctx); + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; sap_ctx->sap_status = eSAP_STATUS_SUCCESS; close_session: diff --git a/core/sap/src/sap_fsm.c b/core/sap/src/sap_fsm.c index e3c6da7f4aaf..788ee6c605f4 100644 --- a/core/sap/src/sap_fsm.c +++ b/core/sap/src/sap_fsm.c @@ -846,6 +846,7 @@ QDF_STATUS sap_channel_sel(struct sap_context *sap_context) uint8_t vdev_id; uint32_t scan_id; uint8_t *self_mac; + uint32_t default_op_freq; mac_handle = cds_get_context(QDF_MODULE_ID_SME); if (!mac_handle) { @@ -861,7 +862,7 @@ QDF_STATUS sap_channel_sel(struct sap_context *sap_context) FL("Invalid MAC context")); return QDF_STATUS_E_FAILURE; } - if (sap_context->chan_freq) + if (sap_context->fsm_state != SAP_STARTED && sap_context->chan_freq) return sap_validate_chan(sap_context, true, false); if (policy_mgr_concurrent_beaconing_sessions_running(mac_ctx->psoc) || @@ -956,12 +957,13 @@ QDF_STATUS sap_channel_sel(struct sap_context *sap_context) QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, FL("SAP Configuring default ch, Ch_freq=%d"), sap_context->chan_freq); - sap_context->chan_freq = sap_select_default_oper_chan( - sap_context->acs_cfg); + default_op_freq = sap_select_default_oper_chan( + sap_context->acs_cfg); + wlansap_set_acs_ch_freq(sap_context, default_op_freq); if (sap_context->freq_list) { - sap_context->chan_freq = - sap_context->freq_list[0]; + wlansap_set_acs_ch_freq( + sap_context, sap_context->freq_list[0]); qdf_mem_free(sap_context->freq_list); sap_context->freq_list = NULL; sap_context->num_of_channel = 0; @@ -974,6 +976,7 @@ QDF_STATUS sap_channel_sel(struct sap_context *sap_context) qdf_ret_status = QDF_STATUS_E_FAILURE; goto release_vdev_ref; } else { + wlansap_dump_acs_ch_freq(sap_context); host_log_acs_scan_start(scan_id, vdev_id); } #ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE @@ -990,6 +993,8 @@ QDF_STATUS sap_channel_sel(struct sap_context *sap_context) } #endif + wlansap_dump_acs_ch_freq(sap_context); + qdf_ret_status = QDF_STATUS_SUCCESS; release_vdev_ref: diff --git a/core/sap/src/sap_internal.h b/core/sap/src/sap_internal.h index aeda026d28b2..06432a26fdf5 100644 --- a/core/sap/src/sap_internal.h +++ b/core/sap/src/sap_internal.h @@ -126,6 +126,10 @@ struct sap_context { uint32_t chan_freq; uint32_t sec_ch_freq; +#ifdef DCS_INTERFERENCE_DETECTION + qdf_freq_t dcs_ch_freq; +#endif + /* Include the SME(CSR) sessionId here */ uint8_t sessionId; diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c index 8ec7c40f13de..5e60e3f7bce3 100644 --- a/core/sap/src/sap_module.c +++ b/core/sap/src/sap_module.c @@ -518,7 +518,7 @@ wlansap_set_scan_acs_channel_params(struct sap_config *config, } /* Channel selection is auto or configured */ - psap_ctx->chan_freq = config->chan_freq; + wlansap_set_acs_ch_freq(psap_ctx, config->chan_freq); psap_ctx->dfs_mode = config->acs_dfs_mode; #ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH psap_ctx->cc_switch_mode = config->cc_switch_mode; @@ -1317,6 +1317,8 @@ static char *sap_get_csa_reason_str(enum sap_csa_reason_code reason) return "CONCURRENT_NAN_EVENT"; case CSA_REASON_BAND_RESTRICTED: return "BAND_RESTRICTED"; + case CSA_REASON_DCS: + return "DCS"; default: return "UNKNOWN"; } @@ -2385,6 +2387,7 @@ void sap_undo_acs(struct sap_context *sap_ctx, struct sap_config *sap_cfg) acs_cfg->master_ch_list_count = 0; acs_cfg->acs_mode = false; sap_ctx->num_of_channel = 0; + wlansap_dcs_set_vdev_wlan_interference_mitigation(sap_ctx, false); } QDF_STATUS wlansap_acs_chselect(struct sap_context *sap_context, @@ -3036,3 +3039,150 @@ qdf_freq_t wlansap_get_chan_band_restrict(struct sap_context *sap_ctx) return restart_freq; } +#ifdef DCS_INTERFERENCE_DETECTION +QDF_STATUS wlansap_dcs_set_vdev_wlan_interference_mitigation( + struct sap_context *sap_context, + bool wlan_interference_mitigation_enable) +{ + struct mac_context *mac; + + if (!sap_context) { + sap_err("Invalid SAP context pointer"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + mac->sap.dcs_info. + wlan_interference_mitigation_enable[sap_context->sessionId] = + wlan_interference_mitigation_enable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_dcs_set_wlan_interference_mitigation_on_band( + struct sap_context *sap_context, + struct sap_config *sap_cfg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool wlan_interference_mitigation_enable = false; + + if (WLAN_REG_IS_5GHZ_CH_FREQ(sap_cfg->acs_cfg.pri_ch_freq)) + wlan_interference_mitigation_enable = true; + + status = wlansap_dcs_set_vdev_wlan_interference_mitigation( + sap_context, + wlan_interference_mitigation_enable); + return status; +} + +QDF_STATUS wlansap_dcs_set_vdev_starting(struct sap_context *sap_context, + bool vdev_starting) +{ + struct mac_context *mac; + + if (!sap_context) { + sap_err("Invalid SAP context pointer"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + mac->sap.dcs_info.is_vdev_starting[sap_context->sessionId] = + vdev_starting; + + return QDF_STATUS_SUCCESS; +} + +bool wlansap_dcs_is_wlan_interference_mitigation_enabled( + struct sap_context *sap_context) +{ + struct mac_context *mac; + + if (!sap_context) { + sap_err("Invalid SAP context pointer"); + return false; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return false; + } + + return mac->sap.dcs_info. + wlan_interference_mitigation_enable[sap_context->sessionId]; +} + +qdf_freq_t wlansap_dcs_get_freq(struct sap_context *sap_context) +{ + if (!sap_context) { + sap_err("Invalid SAP context pointer"); + return false; + } + + return sap_context->dcs_ch_freq; +} + +void wlansap_dump_acs_ch_freq(struct sap_context *sap_context) +{ + if (!sap_context) { + sap_err("Invalid sap_debug"); + return; + } + + if (sap_context->fsm_state == SAP_STARTED) + sap_info("ACS dump DCS freq=%d", sap_context->dcs_ch_freq); + else + sap_info("ACS dump ch_freq=%d", sap_context->chan_freq); +} + +void wlansap_set_acs_ch_freq(struct sap_context *sap_context, + qdf_freq_t ch_freq) +{ + if (!sap_context) { + sap_err("Invalid sap_debug"); + return; + } + + if (sap_context->fsm_state == SAP_STARTED) { + sap_context->dcs_ch_freq = ch_freq; + sap_debug("ACS configuring dcs_ch_freq=%d", + sap_context->dcs_ch_freq); + } else { + sap_context->chan_freq = ch_freq; + sap_debug("ACS configuring ch_freq=%d", + sap_context->chan_freq); + } +} +#else +void wlansap_dump_acs_ch_freq(struct sap_context *sap_context) +{ + if (!sap_context) { + sap_err("Invalid sap_debug"); + return; + } + + sap_info("ACS dump ch_freq=%d", sap_context->chan_freq); +} + +void wlansap_set_acs_ch_freq(struct sap_context *sap_context, + qdf_freq_t ch_freq) +{ + if (!sap_context) { + sap_err("Invalid sap_debug"); + return; + } + + sap_context->chan_freq = ch_freq; + sap_debug("ACS configuring ch_freq=%d", sap_context->chan_freq); +} +#endif diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c index 94c9a8a2a6b5..7e0c2d014644 100644 --- a/core/wma/src/wma_dev_if.c +++ b/core/wma/src/wma_dev_if.c @@ -87,6 +87,10 @@ #include "wlan_utility.h" #include "wlan_coex_ucfg_api.h" +#ifdef DCS_INTERFERENCE_DETECTION +#include +#endif + QDF_STATUS wma_find_vdev_id_by_addr(tp_wma_handle wma, uint8_t *addr, uint8_t *vdev_id) { @@ -1183,6 +1187,81 @@ QDF_STATUS wma_handle_channel_switch_resp(tp_wma_handle wma, return QDF_STATUS_SUCCESS; } +#ifdef DCS_INTERFERENCE_DETECTION +/** + * wma_dcs_clear_vdev_starting() - clear vdev starting within dcs information + * @mac_ctx: mac context + * @vdev_id: vdev id + * + * This function is used to clear vdev starting within dcs information + * + * Return: None + */ +static void wma_dcs_clear_vdev_starting(struct mac_context *mac_ctx, + uint32_t vdev_id) +{ + mac_ctx->sap.dcs_info.is_vdev_starting[vdev_id] = false; +} + +/** + * wma_dcs_wlan_interference_mitigation_enable() - enable wlan + * interference mitigation + * @mac_ctx: mac context + * @mac_id: mac id + * @vdev_id: vdev id + * + * This function is used to enable wlan interference mitigation through + * send dcs command + * + * Return: None + */ +static void wma_dcs_wlan_interference_mitigation_enable( + struct mac_context *mac_ctx, + uint32_t mac_id, + uint32_t vdev_id) +{ + int vdev_index; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t count; + bool wlan_interference_mitigation_enable = + mac_ctx->sap.dcs_info. + wlan_interference_mitigation_enable[vdev_id]; + + count = policy_mgr_get_sap_go_count_on_mac( + mac_ctx->psoc, list, mac_id); + + for (vdev_index = 0; vdev_index < count; vdev_index++) { + if (mac_ctx->sap.dcs_info.is_vdev_starting[list[vdev_index]]) { + WMA_LOGE("vdev %d: does not finish restart", + list[vdev_index]); + return; + } + wlan_interference_mitigation_enable = + wlan_interference_mitigation_enable || + mac_ctx->sap.dcs_info. + wlan_interference_mitigation_enable[list[vdev_index]]; + } + + if (wlan_interference_mitigation_enable) + ucfg_config_dcs_enable( + mac_ctx->psoc, mac_id, CAP_DCS_WLANIM); + ucfg_wlan_dcs_cmd(mac_ctx->psoc, mac_id, true); +} +#else +static void wma_dcs_wlan_interference_mitigation_enable( + struct mac_context *mac_ctx, + uint32_t mac_id, + uint32_t vdev_id) +{ +} + + +static void wma_dcs_clear_vdev_starting(struct mac_context *mac_ctx, + uint32_t vdev_id) +{ +} +#endif + QDF_STATUS wma_vdev_start_resp_handler(struct vdev_mlme_obj *vdev_mlme, struct vdev_start_response *rsp) { @@ -1190,9 +1269,7 @@ QDF_STATUS wma_vdev_start_resp_handler(struct vdev_mlme_obj *vdev_mlme, struct wma_txrx_node *iface; target_resource_config *wlan_res_cfg; struct wlan_objmgr_psoc *psoc; -#ifdef FEATURE_AP_MCC_CH_AVOIDANCE struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); -#endif QDF_STATUS status; enum vdev_assoc_type assoc_type = VDEV_ASSOC; struct vdev_mlme_obj *mlme_obj; @@ -1208,14 +1285,12 @@ QDF_STATUS wma_vdev_start_resp_handler(struct vdev_mlme_obj *vdev_mlme, return QDF_STATUS_E_FAILURE; } -#ifdef FEATURE_AP_MCC_CH_AVOIDANCE if (!mac_ctx) { WMA_LOGE("%s: Failed to get mac_ctx", __func__); policy_mgr_set_do_hw_mode_change_flag( psoc, false); return QDF_STATUS_E_FAILURE; } -#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ wlan_res_cfg = lmac_get_tgt_res_cfg(psoc); if (!wlan_res_cfg) { @@ -1257,6 +1332,12 @@ QDF_STATUS wma_vdev_start_resp_handler(struct vdev_mlme_obj *vdev_mlme, } iface = &wma->interfaces[rsp->vdev_id]; + if (wma_is_vdev_in_ap_mode(wma, rsp->vdev_id)) { + wma_dcs_clear_vdev_starting(mac_ctx, rsp->vdev_id); + wma_dcs_wlan_interference_mitigation_enable(mac_ctx, + iface->mac_id, + rsp->vdev_id); + } #ifdef FEATURE_AP_MCC_CH_AVOIDANCE if (rsp->status == QDF_STATUS_SUCCESS