Procházet zdrojové kódy

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
Liangwei Dong před 6 roky
rodič
revize
ad89c765fd

+ 9 - 0
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,

+ 32 - 5
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__);
 

+ 10 - 2
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: