From ad89c765fdb02178d890e13cedb85a22e48478d2 Mon Sep 17 00:00:00 2001 From: Liangwei Dong Date: Fri, 1 Jun 2018 01:56:23 -0400 Subject: [PATCH] qcacld-3.0: Fix pre cac work thread hung wlan_hdd_sap_pre_cac_success run in the work thread scheduled by sap_pre_cac_work. But hdd_stop_adapter will call cds_flush_work(&hdd_ctx->sap_pre_cac_work); That means the work waits itself to finish. The Fix is to add flag to hdd_stop_adapter to identify the "stop" running in the work handler and skip the "sync" cancel the work self. Change-Id: I875c2f14ffd54272fc9ea0df1cecc6dd1171e310 CRs-Fixed: 2252085 --- core/hdd/inc/wlan_hdd_main.h | 9 ++++++++ core/hdd/src/wlan_hdd_hostapd.c | 37 ++++++++++++++++++++++++++++----- core/hdd/src/wlan_hdd_main.c | 12 +++++++++-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index ceb054b500a1..8bcffb47123f 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -2057,6 +2057,15 @@ void hdd_deinit_adapter(struct hdd_context *hdd_ctx, bool rtnl_held); QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter); + +enum hdd_adapter_stop_flag_t { + HDD_IN_CAC_WORK_TH_CONTEXT = 0x00000001, +}; + +QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + enum hdd_adapter_stop_flag_t flag); + void hdd_set_station_ops(struct net_device *dev); uint8_t *wlan_hdd_get_intf_addr(struct hdd_context *hdd_ctx); void wlan_hdd_release_intf_addr(struct hdd_context *hdd_ctx, diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index e9bb236a7ad0..930b0962aa22 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -1030,6 +1030,32 @@ static int wlan_hdd_set_pre_cac_complete_status(struct hdd_adapter *ap_adapter, return 0; } +/** + * hdd_check_adapter() - check adapter existing or not + * @adapter: adapter + * + * Check adapter in the hdd global list or not + * + * Return: true if adapter exists. + */ +static bool hdd_check_adapter(struct hdd_adapter *adapter) +{ + struct hdd_adapter *temp; + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return false; + } + hdd_for_each_adapter(hdd_ctx, temp) { + if (temp == adapter) + return true; + } + + return false; +} + /** * __wlan_hdd_sap_pre_cac_failure() - Process the pre cac failure * @data: AP adapter @@ -1046,7 +1072,7 @@ static void __wlan_hdd_sap_pre_cac_failure(void *data) hdd_enter(); adapter = (struct hdd_adapter *) data; - if (!adapter || + if (!adapter || !hdd_check_adapter(adapter) || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { hdd_err("SAP Pre CAC adapter invalid"); return; @@ -1060,7 +1086,7 @@ static void __wlan_hdd_sap_pre_cac_failure(void *data) wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes); - hdd_stop_adapter(hdd_ctx, adapter); + hdd_stop_adapter_ext(hdd_ctx, adapter, HDD_IN_CAC_WORK_TH_CONTEXT); hdd_close_adapter(hdd_ctx, adapter, false); } @@ -1097,8 +1123,9 @@ static void wlan_hdd_sap_pre_cac_success(void *data) hdd_enter(); adapter = (struct hdd_adapter *) data; - if (!adapter) { - hdd_err("AP adapter is NULL"); + if (!adapter || !hdd_check_adapter(adapter) || + adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("SAP Pre CAC adapter invalid"); return; } @@ -1111,7 +1138,7 @@ static void wlan_hdd_sap_pre_cac_success(void *data) cds_ssr_protect(__func__); wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes); - hdd_stop_adapter(hdd_ctx, adapter); + hdd_stop_adapter_ext(hdd_ctx, adapter, HDD_IN_CAC_WORK_TH_CONTEXT); hdd_close_adapter(hdd_ctx, adapter, false); cds_ssr_unprotect(__func__); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index e271bc422178..6bb6e2bacc6f 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -4831,8 +4831,8 @@ QDF_STATUS hdd_close_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *ad /* cleanup adapter */ policy_mgr_clear_concurrency_mode(hdd_ctx->hdd_psoc, adapter->device_mode); - hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); hdd_remove_adapter(hdd_ctx, adapter); + hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); /* conditionally restart the bw timer */ hdd_bus_bw_compute_timer_try_start(hdd_ctx); @@ -4927,6 +4927,13 @@ void wlan_hdd_reset_prob_rspies(struct hdd_adapter *adapter) QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter) +{ + return hdd_stop_adapter_ext(hdd_ctx, adapter, 0); +} + +QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + enum hdd_adapter_stop_flag_t flag) { QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; struct csr_roam_profile *roam_profile; @@ -5058,7 +5065,8 @@ QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, wlansap_reset_sap_config_add_ie(sap_config, eUPDATE_IE_ALL); ucfg_ipa_flush(hdd_ctx->hdd_pdev); - cds_flush_work(&hdd_ctx->sap_pre_cac_work); + if (!(flag & HDD_IN_CAC_WORK_TH_CONTEXT)) + cds_flush_work(&hdd_ctx->sap_pre_cac_work); /* fallthrough */ case QDF_P2P_GO_MODE: