Jelajahi Sumber

qcacld-3.0: Avoid race condition in antenna switch operation

qcacld-2.0 to qcacld-3.0 propagation

When the TDLS traffic flows continuously between the two
peers and if the antenna switch command comes from the
user, it creates a race condition and blocks the
antenna switch operation.
Add a new transition state in TDLS to avoid this race
condition.

Change-Id: I1c9b183c460e1401bd1ee2631489c57778ec665b
CRs-Fixed: 971505
Kabilan Kannan 8 tahun lalu
induk
melakukan
ff89f748c1

+ 2 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -1298,6 +1298,8 @@ struct hdd_context_s {
 	bool enable_tdls_connection_tracker;
 	uint8_t tdls_external_peer_count;
 	bool tdls_nss_switch_in_progress;
+	bool tdls_nss_teardown_complete;
+	enum tdls_nss_transition_type tdls_nss_transition_mode;
 	int32_t tdls_teardown_peers_cnt;
 	struct tdls_set_state_info set_state_info;
 #endif

+ 12 - 0
core/hdd/inc/wlan_hdd_tdls.h

@@ -144,6 +144,18 @@ enum tdls_spatial_streams {
 	TDLS_NSS_2x2_MODE = 0xff,
 };
 
+/**
+ * enum tdls_nss_transition_type - TDLS NSS transition states
+ * @TDLS_NSS_TRANSITION_UNKNOWN: default state
+ * @TDLS_NSS_TRANSITION_2x2_to_1x1: transition from 2x2 to 1x1 stream
+ * @TDLS_NSS_TRANSITION_1x1_to_2x2: transition from 1x1 to 2x2 stream
+ */
+enum tdls_nss_transition_type {
+	TDLS_NSS_TRANSITION_UNKNOWN = 0,
+	TDLS_NSS_TRANSITION_2x2_to_1x1,
+	TDLS_NSS_TRANSITION_1x1_to_2x2,
+};
+
 /**
  * enum tTDLSCapType - tdls capability type
  *

+ 11 - 0
core/hdd/src/wlan_hdd_ioctl.c

@@ -6691,6 +6691,17 @@ static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter,
 		 hdd_ctx->current_antenna_mode);
 	ret = 0;
 exit:
+#ifdef FEATURE_WLAN_TDLS
+	/* Reset tdls NSS flags */
+	if (hdd_ctx->tdls_nss_switch_in_progress &&
+	    hdd_ctx->tdls_nss_teardown_complete) {
+		hdd_ctx->tdls_nss_switch_in_progress = false;
+		hdd_ctx->tdls_nss_teardown_complete = false;
+	}
+	hdd_info("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
+		  hdd_ctx->tdls_nss_switch_in_progress,
+		  hdd_ctx->tdls_nss_teardown_complete);
+#endif
 	hdd_info("Set antenna status: %d current mode: %d",
 		 ret, hdd_ctx->current_antenna_mode);
 	return ret;

+ 33 - 6
core/hdd/src/wlan_hdd_tdls.c

@@ -654,6 +654,8 @@ void hdd_tdls_context_init(hdd_context_t *hdd_ctx)
 	hdd_ctx->tdls_external_peer_count = 0;
 	hdd_ctx->set_state_info.set_state_cnt = 0;
 	hdd_ctx->set_state_info.vdev_id = 0;
+	hdd_ctx->tdls_nss_teardown_complete = false;
+	hdd_ctx->tdls_nss_transition_mode = TDLS_NSS_TRANSITION_UNKNOWN;
 
 	/* This flag will set  be true, only when device operates in
 	 * standalone STA mode
@@ -4082,8 +4084,24 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
 		mutex_lock(&pHddCtx->tdls_lock);
 		if (pHddCtx->tdls_teardown_peers_cnt != 0)
 			pHddCtx->tdls_teardown_peers_cnt--;
-		if (pHddCtx->tdls_teardown_peers_cnt == 0)
-			pHddCtx->tdls_nss_switch_in_progress = false;
+		if (pHddCtx->tdls_teardown_peers_cnt == 0) {
+			if (pHddCtx->tdls_nss_transition_mode ==
+			    TDLS_NSS_TRANSITION_1x1_to_2x2) {
+				/* TDLS NSS switch is fully completed, so
+				 * reset the flags.
+				 */
+				hdd_info("TDLS NSS switch is fully completed");
+				pHddCtx->tdls_nss_switch_in_progress = false;
+				pHddCtx->tdls_nss_teardown_complete = false;
+			} else {
+				/* TDLS NSS switch is not yet completed, but
+				 * tdls teardown is completed for all the
+				 * peers.
+				 */
+				hdd_info("TDLS teardown is completed and NSS switch still in progress");
+				pHddCtx->tdls_nss_teardown_complete = true;
+			}
+		}
 		mutex_unlock(&pHddCtx->tdls_lock);
 	}
 
@@ -5829,11 +5847,16 @@ static int wlan_hdd_tdls_teardown_links(hdd_context_t *hddctx,
 		hdd_info("TDLS peers to be torn down = %d",
 			 hddctx->tdls_teardown_peers_cnt);
 		/*  Antenna switch 2x2 to 1x1 */
-		if (mode == HDD_ANTENNA_MODE_1X1)
+		if (mode == HDD_ANTENNA_MODE_1X1) {
+			hddctx->tdls_nss_transition_mode =
+				TDLS_NSS_TRANSITION_2x2_to_1x1;
 			ret = -EAGAIN;
-		else
+		} else {
 		/*  Antenna switch 1x1 to 2x2 */
+			hddctx->tdls_nss_transition_mode =
+				TDLS_NSS_TRANSITION_1x1_to_2x2;
 			ret = 0;
+		}
 		hdd_info("TDLS teardown for antenna switch operation starts");
 	}
 	mutex_unlock(&hddctx->tdls_lock);
@@ -5858,8 +5881,12 @@ int wlan_hdd_tdls_antenna_switch(hdd_context_t *hdd_ctx,
 
 	/* Check whether TDLS antenna switch is in progress */
 	if (hdd_ctx->tdls_nss_switch_in_progress) {
-		hdd_err("TDLS antenna switch is in progress");
-		return -EAGAIN;
+		if (hdd_ctx->tdls_nss_teardown_complete == false) {
+			hdd_err("TDLS antenna switch is in progress");
+			return -EAGAIN;
+		} else {
+			goto tdls_ant_sw_done;
+		}
 	}
 
 	/* Check whether TDLS is connected or not */