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
Dieser Commit ist enthalten in:
Kabilan Kannan
2016-08-15 18:14:10 -07:00
committet von qcabuildsw
Ursprung 35cc2cf07c
Commit ff89f748c1
4 geänderte Dateien mit 58 neuen und 6 gelöschten Zeilen

Datei anzeigen

@@ -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

Datei anzeigen

@@ -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
*

Datei anzeigen

@@ -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;

Datei anzeigen

@@ -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 */