소스 검색

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
gaurank kathpalia 5 년 전
부모
커밋
7aed85ed22
4개의 변경된 파일16개의 추가작업 그리고 8개의 파일을 삭제
  1. 4 1
      core/hdd/inc/wlan_hdd_main.h
  2. 1 5
      core/hdd/src/wlan_hdd_cfg80211.c
  3. 3 0
      core/hdd/src/wlan_hdd_hostapd.c
  4. 8 2
      core/hdd/src/wlan_hdd_main.c

+ 4 - 1
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
 #define NUM_CPUS 1
 #endif
 #endif
 
 
+#define ACS_COMPLETE_TIMEOUT 3000
+
 #define HDD_PSOC_IDLE_SHUTDOWN_SUSPEND_DELAY (1000)
 #define HDD_PSOC_IDLE_SHUTDOWN_SUSPEND_DELAY (1000)
 /**
 /**
  * enum hdd_adapter_flags - event bitmap flags registered net device
  * enum hdd_adapter_flags - event bitmap flags registered net device
@@ -1043,7 +1045,7 @@ struct hdd_context;
  * @mic_work: mic work information
  * @mic_work: mic work information
  * @gpio_tsf_sync_work: work to sync send TSF CAP WMI command
  * @gpio_tsf_sync_work: work to sync send TSF CAP WMI command
  * @cache_sta_count: number of currently cached stations
  * @cache_sta_count: number of currently cached stations
- *
+ * @acs_complete_event: acs complete event
  */
  */
 struct hdd_adapter {
 struct hdd_adapter {
 	/* Magic cookie for adapter sanity verification.  Note that this
 	/* Magic cookie for adapter sanity verification.  Note that this
@@ -1168,6 +1170,7 @@ struct hdd_adapter {
 	} session;
 	} session;
 
 
 	qdf_atomic_t ch_switch_in_progress;
 	qdf_atomic_t ch_switch_in_progress;
+	qdf_event_t acs_complete_event;
 
 
 #ifdef WLAN_FEATURE_TSF
 #ifdef WLAN_FEATURE_TSF
 	/* tsf value received from firmware */
 	/* tsf value received from firmware */

+ 1 - 5
core/hdd/src/wlan_hdd_cfg80211.c

@@ -2760,6 +2760,7 @@ static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy,
 		return -EINVAL;
 		return -EINVAL;
 	} else {
 	} else {
 		qdf_atomic_set(&adapter->session.ap.acs_in_progress, 1);
 		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,
 	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();
 	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_stop_adapter(hdd_ctx, adapter);
 	hdd_deinit_adapter(hdd_ctx, adapter, true);
 	hdd_deinit_adapter(hdd_ctx, adapter, true);
 	adapter->device_mode = new_mode;
 	adapter->device_mode = new_mode;

+ 3 - 0
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;
 			sap_event->sapevt.sap_ch_selected.ch_width;
 		wlan_hdd_cfg80211_acs_ch_select_evt(adapter);
 		wlan_hdd_cfg80211_acs_ch_select_evt(adapter);
 		qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0);
 		qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0);
+		qdf_event_set(&adapter->acs_complete_event);
+
 		return QDF_STATUS_SUCCESS;
 		return QDF_STATUS_SUCCESS;
 	case eSAP_ECSA_CHANGE_CHAN_IND:
 	case eSAP_ECSA_CHANGE_CHAN_IND:
 		hdd_debug("Channel change indication from peer for channel %d",
 		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);
 		clear_bit(WMM_INIT_DONE, &adapter->event_flags);
 	}
 	}
 	qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0);
 	qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0);
+
 	hdd_softap_deinit_tx_rx(adapter);
 	hdd_softap_deinit_tx_rx(adapter);
 	/*
 	/*
 	 * if we are being called during driver unload,
 	 * if we are being called during driver unload,

+ 8 - 2
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);
 	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_list_create(&adapter->blocked_scan_request_q, WLAN_MAX_SCAN_COUNT);
 	qdf_mutex_create(&adapter->blocked_scan_request_q_lock);
 	qdf_mutex_create(&adapter->blocked_scan_request_q_lock);
+	qdf_event_create(&adapter->acs_complete_event);
 
 
 	if (QDF_STATUS_SUCCESS == status) {
 	if (QDF_STATUS_SUCCESS == status) {
 		/* Add it to the hdd's session list. */
 		/* 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_list_destroy(&adapter->blocked_scan_request_q);
 	qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock);
 	qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock);
 	policy_mgr_clear_concurrency_mode(hdd_ctx->psoc, adapter->device_mode);
 	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);
 	hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held);
 
 
 	if (hdd_ctx->current_intf_count != 0)
 	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:
 	case QDF_P2P_GO_MODE:
 		cds_flush_work(&adapter->sap_stop_bss_work);
 		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);
 		wlan_hdd_undo_acs(adapter);
 
 
 		if (adapter->device_mode == QDF_P2P_GO_MODE)
 		if (adapter->device_mode == QDF_P2P_GO_MODE)