From 7aed85ed22098d8f0bcbf5f7cffc5585e56a638f Mon Sep 17 00:00:00 2001 From: gaurank kathpalia Date: Thu, 10 Oct 2019 15:12:54 +0530 Subject: [PATCH] qcacld-3.0: Wait for ACS rather than iface change fail Currently the driver checks for the ACS in progress in change iface and returns fail if the ACS is in progress. The return status is not checked by the kernel and it assumes that the interface change is successfull, which may lead to out of sync between driver and kernel. Fix is to wait for ACS completion if the iface change or interface down is triggered in between ACS. Change-Id: Iaabd42fc959a533041b18b181e1b63493f17e0a5 CRs-Fixed: 2541325 --- core/hdd/inc/wlan_hdd_main.h | 5 ++++- core/hdd/src/wlan_hdd_cfg80211.c | 6 +----- core/hdd/src/wlan_hdd_hostapd.c | 3 +++ core/hdd/src/wlan_hdd_main.c | 10 ++++++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 28bbc266be80..b621e6971212 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -197,6 +197,8 @@ static inline bool in_compat_syscall(void) { return is_compat_task(); } #define NUM_CPUS 1 #endif +#define ACS_COMPLETE_TIMEOUT 3000 + #define HDD_PSOC_IDLE_SHUTDOWN_SUSPEND_DELAY (1000) /** * enum hdd_adapter_flags - event bitmap flags registered net device @@ -1043,7 +1045,7 @@ struct hdd_context; * @mic_work: mic work information * @gpio_tsf_sync_work: work to sync send TSF CAP WMI command * @cache_sta_count: number of currently cached stations - * + * @acs_complete_event: acs complete event */ struct hdd_adapter { /* Magic cookie for adapter sanity verification. Note that this @@ -1168,6 +1170,7 @@ struct hdd_adapter { } session; qdf_atomic_t ch_switch_in_progress; + qdf_event_t acs_complete_event; #ifdef WLAN_FEATURE_TSF /* tsf value received from firmware */ diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index a4f225078887..65bce41f270e 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -2760,6 +2760,7 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, return -EINVAL; } else { qdf_atomic_set(&adapter->session.ap.acs_in_progress, 1); + qdf_event_reset(&adapter->acs_complete_event); } ret = wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX, data, @@ -15561,11 +15562,6 @@ static int hdd_change_adapter_mode(struct hdd_adapter *adapter, hdd_enter(); - if (test_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags)) { - hdd_warn("Can't change interface: ACS in progress"); - return -EBUSY; - } - hdd_stop_adapter(hdd_ctx, adapter); hdd_deinit_adapter(hdd_ctx, adapter, true); adapter->device_mode = new_mode; diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 274ceff38123..5a8352d9cc60 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -2600,6 +2600,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event, sap_event->sapevt.sap_ch_selected.ch_width; wlan_hdd_cfg80211_acs_ch_select_evt(adapter); qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0); + qdf_event_set(&adapter->acs_complete_event); + return QDF_STATUS_SUCCESS; case eSAP_ECSA_CHANGE_CHAN_IND: hdd_debug("Channel change indication from peer for channel %d", @@ -3459,6 +3461,7 @@ void hdd_deinit_ap_mode(struct hdd_context *hdd_ctx, clear_bit(WMM_INIT_DONE, &adapter->event_flags); } qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0); + hdd_softap_deinit_tx_rx(adapter); /* * if we are being called during driver unload, diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 5a766ed47169..460c48599578 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -5622,6 +5622,7 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio INIT_WORK(&adapter->scan_block_work, wlan_hdd_cfg80211_scan_block_cb); qdf_list_create(&adapter->blocked_scan_request_q, WLAN_MAX_SCAN_COUNT); qdf_mutex_create(&adapter->blocked_scan_request_q_lock); + qdf_event_create(&adapter->acs_complete_event); if (QDF_STATUS_SUCCESS == status) { /* Add it to the hdd's session list. */ @@ -5679,7 +5680,7 @@ static void __hdd_close_adapter(struct hdd_context *hdd_ctx, qdf_list_destroy(&adapter->blocked_scan_request_q); qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock); policy_mgr_clear_concurrency_mode(hdd_ctx->psoc, adapter->device_mode); - + qdf_event_destroy(&adapter->acs_complete_event); hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); if (hdd_ctx->current_intf_count != 0) @@ -5970,7 +5971,12 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, case QDF_P2P_GO_MODE: cds_flush_work(&adapter->sap_stop_bss_work); - qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0); + if (qdf_atomic_read(&adapter->session.ap.acs_in_progress)) { + hdd_info("ACS in progress, wait for complete"); + qdf_wait_for_event_completion( + &adapter->acs_complete_event, + ACS_COMPLETE_TIMEOUT); + } wlan_hdd_undo_acs(adapter); if (adapter->device_mode == QDF_P2P_GO_MODE)