qcacmn: Dynamic antenna switch in TDLS operation
Support dynamic antenna switch in TDLS: 1. If TDLS NSS is configured to be 1x1, TDLS connections not teardown; 2. When antenna mode switched from 2x2 to 1x1, TDLS connections teared down and EAGAIN returned; When antenna mode switched from 1x1 to 2x2, TDLS connections is still teardown, but success in one trial. Change-Id: I1877002122a96dc8f40c796f8a1b938199d3b67a CRs-Fixed: 2080461
This commit is contained in:
@@ -44,11 +44,13 @@
|
||||
* @tdls_mgmt_comp: Completion to send tdls mgmt packets
|
||||
* @tdls_link_establish_req_comp: Completion to establish link, sync to
|
||||
* send establish params to firmware, not used today.
|
||||
* @tdls_teardown_comp: tdls teardown completion event
|
||||
* @tdls_teardown_comp: Completion to teardown tdls peer
|
||||
* @tdls_user_cmd_comp: tdls user command completion event
|
||||
* @tdls_antenna_switch_comp: Completion to switch antenna
|
||||
* @tdls_add_peer_status: Peer status after add peer
|
||||
* @mgmt_tx_completion_status: Tdls mgmt frames TX completion status code
|
||||
* @tdls_user_cmd_len: tdls user command written buffer length
|
||||
* @tdls_antenna_switch_status: return status after antenna switch
|
||||
*/
|
||||
struct osif_tdls_vdev {
|
||||
struct completion tdls_add_peer_comp;
|
||||
@@ -57,9 +59,11 @@ struct osif_tdls_vdev {
|
||||
struct completion tdls_link_establish_req_comp;
|
||||
struct completion tdls_teardown_comp;
|
||||
struct completion tdls_user_cmd_comp;
|
||||
struct completion tdls_antenna_switch_comp;
|
||||
QDF_STATUS tdls_add_peer_status;
|
||||
uint32_t mgmt_tx_completion_status;
|
||||
uint32_t tdls_user_cmd_len;
|
||||
int tdls_antenna_switch_status;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -183,6 +187,15 @@ int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_pdev *pdev,
|
||||
uint16_t status_code, uint32_t peer_capability,
|
||||
const uint8_t *buf, size_t len);
|
||||
|
||||
/**
|
||||
* wlan_tdls_antenna_switch() - process tdls antenna switch
|
||||
* @vdev: vdev object
|
||||
* @mode: antenna mode
|
||||
*
|
||||
* Return: 0 on success; -EAGAIN to retry
|
||||
*/
|
||||
int wlan_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev, uint32_t mode);
|
||||
|
||||
/**
|
||||
* wlan_cfg80211_tdls_event_callback() - callback for tdls module
|
||||
* @userdata: user data
|
||||
|
@@ -68,6 +68,7 @@ QDF_STATUS wlan_cfg80211_tdls_priv_init(struct vdev_osif_priv *osif_priv)
|
||||
init_completion(&tdls_priv->tdls_link_establish_req_comp);
|
||||
init_completion(&tdls_priv->tdls_teardown_comp);
|
||||
init_completion(&tdls_priv->tdls_user_cmd_comp);
|
||||
init_completion(&tdls_priv->tdls_antenna_switch_comp);
|
||||
|
||||
osif_priv->osif_tdls = tdls_priv;
|
||||
|
||||
@@ -814,6 +815,47 @@ error_mgmt_req:
|
||||
return status;
|
||||
}
|
||||
|
||||
int wlan_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev, uint32_t mode)
|
||||
{
|
||||
struct vdev_osif_priv *osif_priv;
|
||||
struct osif_tdls_vdev *tdls_priv;
|
||||
int ret;
|
||||
unsigned long rc;
|
||||
|
||||
if (!vdev) {
|
||||
cfg80211_err("vdev is NULL");
|
||||
return -EAGAIN;
|
||||
}
|
||||
wlan_objmgr_vdev_get_ref(vdev, WLAN_OSIF_ID);
|
||||
|
||||
osif_priv = wlan_vdev_get_ospriv(vdev);
|
||||
tdls_priv = osif_priv->osif_tdls;
|
||||
|
||||
reinit_completion(&tdls_priv->tdls_antenna_switch_comp);
|
||||
ret = ucfg_tdls_antenna_switch(vdev, mode);
|
||||
if (QDF_IS_STATUS_ERROR(ret)) {
|
||||
cfg80211_err("ucfg_tdls_antenna_switch failed err %d", ret);
|
||||
ret = -EAGAIN;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = wait_for_completion_timeout(
|
||||
&tdls_priv->tdls_antenna_switch_comp,
|
||||
msecs_to_jiffies(WAIT_TIME_FOR_TDLS_ANTENNA_SWITCH));
|
||||
if (!rc) {
|
||||
cfg80211_err("timeout for tdls antenna switch %ld", rc);
|
||||
ret = -EAGAIN;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = tdls_priv->tdls_antenna_switch_status;
|
||||
cfg80211_debug("tdls antenna switch status:%d", ret);
|
||||
error:
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
wlan_cfg80211_tdls_indicate_discovery(struct tdls_osif_indication *ind)
|
||||
{
|
||||
@@ -896,6 +938,9 @@ void wlan_cfg80211_tdls_event_callback(void *user_data,
|
||||
complete(&tdls_priv->tdls_user_cmd_comp);
|
||||
break;
|
||||
|
||||
case TDLS_EVENT_ANTENNA_SWITCH:
|
||||
tdls_priv->tdls_antenna_switch_status = ind->status;
|
||||
complete(&tdls_priv->tdls_antenna_switch_comp);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include "wlan_tdls_mgmt.h"
|
||||
#include "wlan_tdls_cmds_process.h"
|
||||
#include "wlan_tdls_tgt_api.h"
|
||||
#include "wlan_policy_mgr_api.h"
|
||||
|
||||
static uint16_t tdls_get_connected_peer(struct tdls_soc_priv_obj *soc_obj)
|
||||
{
|
||||
@@ -567,7 +568,7 @@ void tdls_reset_nss(struct tdls_soc_priv_obj *tdls_soc,
|
||||
return;
|
||||
|
||||
if (TDLS_TEARDOWN != action_code ||
|
||||
tdls_soc->tdls_nss_switch_in_progress)
|
||||
!tdls_soc->tdls_nss_switch_in_progress)
|
||||
return;
|
||||
|
||||
if (tdls_soc->tdls_teardown_peers_cnt != 0)
|
||||
@@ -589,6 +590,8 @@ void tdls_reset_nss(struct tdls_soc_priv_obj *tdls_soc,
|
||||
tdls_notice("teardown done & NSS switch in progress");
|
||||
tdls_soc->tdls_nss_teardown_complete = true;
|
||||
}
|
||||
tdls_soc->tdls_nss_transition_mode =
|
||||
TDLS_NSS_TRANSITION_S_UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2182,3 +2185,147 @@ int tdls_set_responder(struct tdls_set_responder_req *set_req)
|
||||
return status;
|
||||
}
|
||||
|
||||
static int tdls_teardown_links(struct tdls_soc_priv_obj *soc_obj, uint32_t mode)
|
||||
{
|
||||
uint8_t staidx;
|
||||
struct tdls_peer *curr_peer;
|
||||
struct tdls_conn_info *conn_rec;
|
||||
int ret = 0;
|
||||
|
||||
conn_rec = soc_obj->tdls_conn_info;
|
||||
for (staidx = 0; staidx < soc_obj->max_num_tdls_sta; staidx++) {
|
||||
if (conn_rec[staidx].sta_id == 0)
|
||||
continue;
|
||||
|
||||
curr_peer = tdls_find_all_peer(soc_obj,
|
||||
conn_rec[staidx].peer_mac.bytes);
|
||||
if (!curr_peer)
|
||||
continue;
|
||||
|
||||
/* if supported only 1x1, skip it */
|
||||
if (curr_peer->spatial_streams == HW_MODE_SS_1x1)
|
||||
continue;
|
||||
|
||||
tdls_debug("Indicate TDLS teardown (staId %d)",
|
||||
curr_peer->sta_id);
|
||||
tdls_indicate_teardown(curr_peer->vdev_priv, curr_peer,
|
||||
TDLS_TEARDOWN_PEER_UNSPEC_REASON);
|
||||
|
||||
soc_obj->tdls_teardown_peers_cnt++;
|
||||
}
|
||||
|
||||
if (soc_obj->tdls_teardown_peers_cnt >= 1) {
|
||||
soc_obj->tdls_nss_switch_in_progress = true;
|
||||
tdls_debug("TDLS peers to be torn down = %d",
|
||||
soc_obj->tdls_teardown_peers_cnt);
|
||||
|
||||
/* set the antenna switch transition mode */
|
||||
if (mode == HW_MODE_SS_1x1) {
|
||||
soc_obj->tdls_nss_transition_mode =
|
||||
TDLS_NSS_TRANSITION_S_2x2_to_1x1;
|
||||
ret = -EAGAIN;
|
||||
} else {
|
||||
soc_obj->tdls_nss_transition_mode =
|
||||
TDLS_NSS_TRANSITION_S_1x1_to_2x2;
|
||||
ret = 0;
|
||||
}
|
||||
tdls_debug("TDLS teardown for antenna switch operation starts");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QDF_STATUS tdls_process_antenna_switch(struct tdls_antenna_switch_request *req)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
struct tdls_soc_priv_obj *soc_obj;
|
||||
struct tdls_vdev_priv_obj *vdev_obj;
|
||||
struct wlan_objmgr_vdev *vdev = NULL;
|
||||
uint32_t vdev_nss;
|
||||
int ant_switch_state = 0;
|
||||
uint32_t vdev_id;
|
||||
enum QDF_OPMODE opmode;
|
||||
uint8_t channel;
|
||||
struct tdls_osif_indication ind;
|
||||
|
||||
if (!req || !req->vdev) {
|
||||
tdls_err("req: %p", req);
|
||||
status = QDF_STATUS_E_INVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
vdev = req->vdev;
|
||||
status = tdls_get_vdev_objects(vdev, &vdev_obj, &soc_obj);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
tdls_err("can't get vdev_obj & soc_obj");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (soc_obj->connected_peer_count == 0)
|
||||
goto ant_sw_done;
|
||||
|
||||
if (soc_obj->tdls_nss_switch_in_progress) {
|
||||
if (!soc_obj->tdls_nss_teardown_complete) {
|
||||
tdls_err("TDLS antenna switch is in progress");
|
||||
goto error;
|
||||
} else {
|
||||
goto ant_sw_done;
|
||||
}
|
||||
}
|
||||
|
||||
vdev_id = wlan_vdev_get_id(vdev);
|
||||
opmode = wlan_vdev_mlme_get_opmode(vdev);
|
||||
channel = policy_mgr_get_channel(soc_obj->soc, opmode, &vdev_id);
|
||||
|
||||
/* Check supported nss for TDLS, if is 1x1, no need to teardown links */
|
||||
if (WLAN_REG_IS_24GHZ_CH(channel))
|
||||
vdev_nss = soc_obj->tdls_configs.tdls_vdev_nss_2g;
|
||||
else
|
||||
vdev_nss = soc_obj->tdls_configs.tdls_vdev_nss_5g;
|
||||
|
||||
if (vdev_nss == HW_MODE_SS_1x1) {
|
||||
tdls_debug("Supported NSS is 1x1, no need to teardown TDLS links");
|
||||
goto ant_sw_done;
|
||||
}
|
||||
|
||||
if (tdls_teardown_links(soc_obj, req->mode) == 0)
|
||||
goto ant_sw_done;
|
||||
|
||||
error:
|
||||
ant_switch_state = -EAGAIN;
|
||||
ant_sw_done:
|
||||
if (soc_obj->tdls_event_cb) {
|
||||
ind.vdev = vdev;
|
||||
ind.status = ant_switch_state;
|
||||
soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
|
||||
TDLS_EVENT_ANTENNA_SWITCH, &ind);
|
||||
}
|
||||
|
||||
if (soc_obj->tdls_nss_switch_in_progress &&
|
||||
soc_obj->tdls_nss_teardown_complete) {
|
||||
soc_obj->tdls_nss_switch_in_progress = false;
|
||||
soc_obj->tdls_nss_teardown_complete = false;
|
||||
}
|
||||
tdls_debug("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
|
||||
soc_obj->tdls_nss_switch_in_progress,
|
||||
soc_obj->tdls_nss_teardown_complete);
|
||||
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
||||
qdf_mem_free(req);
|
||||
return status;
|
||||
}
|
||||
|
||||
QDF_STATUS tdls_antenna_switch_flush_callback(struct scheduler_msg *msg)
|
||||
{
|
||||
struct tdls_antenna_switch_request *req;
|
||||
|
||||
if (!msg || !msg->bodyptr) {
|
||||
tdls_err("msg: 0x%pK, bodyptr: 0x%pK", msg, msg->bodyptr);
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
}
|
||||
req = msg->bodyptr;
|
||||
wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
|
||||
qdf_mem_free(req);
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
@@ -249,6 +249,26 @@ QDF_STATUS tdls_process_remove_force_peer(struct tdls_oper_request *req);
|
||||
*/
|
||||
QDF_STATUS tdls_process_update_peer(struct tdls_update_peer_request *req);
|
||||
|
||||
/**
|
||||
* tdls_process_antenna_switch() - handle TDLS antenna switch
|
||||
* @req: TDLS antenna switch request
|
||||
*
|
||||
* Rely on callback to indicate the antenna switch state to caller.
|
||||
*
|
||||
* Return: QDF_STATUS_SUCCESS if success; other value if failed.
|
||||
*/
|
||||
QDF_STATUS tdls_process_antenna_switch(struct tdls_antenna_switch_request *req);
|
||||
|
||||
/**
|
||||
* tdls_antenna_switch_flush_callback() - flush TDLS antenna switch request
|
||||
* @msg: scheduler message contains tdls antenna switch event
|
||||
*
|
||||
* This function call is invoked when scheduler thread is going down
|
||||
*
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
QDF_STATUS tdls_antenna_switch_flush_callback(struct scheduler_msg *msg);
|
||||
|
||||
/**
|
||||
* tdls_pe_del_peer() - send TDLS delete peer request to PE
|
||||
* @req: TDLS delete peer request
|
||||
|
@@ -292,6 +292,8 @@ QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg)
|
||||
break;
|
||||
case TDLS_NOTIFY_RESET_ADAPTERS:
|
||||
tdls_notify_reset_adapter(msg->bodyptr);
|
||||
case TDLS_CMD_ANTENNA_SWITCH:
|
||||
tdls_process_antenna_switch(msg->bodyptr);
|
||||
break;
|
||||
case TDLS_CMD_GET_ALL_PEERS:
|
||||
tdls_get_all_peers_from_list(msg->bodyptr);
|
||||
|
@@ -68,6 +68,9 @@
|
||||
/** Maximum waittime for TDLS teardown links **/
|
||||
#define WAIT_TIME_FOR_TDLS_TEARDOWN_LINKS 10000
|
||||
|
||||
/** Maximum waittime for TDLS antenna switch **/
|
||||
#define WAIT_TIME_FOR_TDLS_ANTENNA_SWITCH 1000
|
||||
|
||||
#define TDLS_TEARDOWN_PEER_UNREACHABLE 25
|
||||
#define TDLS_TEARDOWN_PEER_UNSPEC_REASON 26
|
||||
|
||||
@@ -185,6 +188,7 @@ enum tdls_feature_mode {
|
||||
* @TDLS_CMD_TEARDOWN_LINKS: notify teardown
|
||||
* @TDLS_NOTIFY_RESET_ADAPTERS: notify adapater reset
|
||||
* @TDLS_CMD_GET_ALL_PEERS: get all the tdls peers from the list
|
||||
* @TDLS_CMD_ANTENNA_SWITCH: dynamic tdls antenna switch
|
||||
*/
|
||||
enum tdls_command_type {
|
||||
TDLS_CMD_TX_ACTION = 1,
|
||||
@@ -206,6 +210,7 @@ enum tdls_command_type {
|
||||
TDLS_CMD_TEARDOWN_LINKS,
|
||||
TDLS_NOTIFY_RESET_ADAPTERS,
|
||||
TDLS_CMD_GET_ALL_PEERS,
|
||||
TDLS_CMD_ANTENNA_SWITCH
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -220,6 +225,7 @@ enum tdls_command_type {
|
||||
* @TDLS_EVENT_SETUP_REQ: setup request
|
||||
* @TDLS_EVENT_TEARDOWN_LINKS_DONE: teardown completion event
|
||||
* @TDLS_EVENT_USER_CMD: tdls user command
|
||||
* @TDLS_EVENT_ANTENNA_SWITCH: antenna switch event
|
||||
*/
|
||||
enum tdls_event_type {
|
||||
TDLS_EVENT_VDEV_STATE_CHANGE = 0,
|
||||
@@ -232,6 +238,7 @@ enum tdls_event_type {
|
||||
TDLS_EVENT_SETUP_REQ,
|
||||
TDLS_EVENT_TEARDOWN_LINKS_DONE,
|
||||
TDLS_EVENT_USER_CMD,
|
||||
TDLS_EVENT_ANTENNA_SWITCH,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -417,6 +424,8 @@ enum tdls_feature_bit {
|
||||
* @tdls_pre_off_chan_bw: tdls off channel bandwidth
|
||||
* @tdls_peer_kickout_threshold: sta kickout threshold for tdls peer
|
||||
* @delayed_trig_framint: delayed trigger frame interval
|
||||
* @tdls_vdev_nss_2g: tdls NSS setting for 2G band
|
||||
* @tdls_vdev_nss_5g: tdls NSS setting for 5G band
|
||||
*/
|
||||
struct tdls_user_config {
|
||||
uint32_t tdls_tx_states_period;
|
||||
@@ -437,6 +446,8 @@ struct tdls_user_config {
|
||||
uint32_t tdls_pre_off_chan_bw;
|
||||
uint32_t tdls_peer_kickout_threshold;
|
||||
uint32_t delayed_trig_framint;
|
||||
uint8_t tdls_vdev_nss_2g;
|
||||
uint8_t tdls_vdev_nss_5g;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1066,4 +1077,13 @@ struct tdls_del_all_tdls_peers {
|
||||
struct qdf_mac_addr bssid;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tdls_antenna_switch_request - TDLS antenna switch request
|
||||
* @vdev: vdev object
|
||||
* @mode: antenna mode, 1x1 or 2x2
|
||||
*/
|
||||
struct tdls_antenna_switch_request {
|
||||
struct wlan_objmgr_vdev *vdev;
|
||||
uint32_t mode;
|
||||
};
|
||||
#endif
|
||||
|
@@ -212,4 +212,14 @@ void ucfg_tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
|
||||
void ucfg_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
|
||||
struct qdf_mac_addr *mac_addr);
|
||||
|
||||
/**
|
||||
* ucfg_tdls_antenna_switch() - tdls antenna switch
|
||||
* @vdev: tdls vdev object
|
||||
* @mode: antenna mode
|
||||
*
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
QDF_STATUS ucfg_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev,
|
||||
uint32_t mode);
|
||||
|
||||
#endif
|
||||
|
@@ -742,3 +742,43 @@ void ucfg_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
|
||||
|
||||
}
|
||||
|
||||
QDF_STATUS ucfg_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev,
|
||||
uint32_t mode)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
struct tdls_antenna_switch_request *req;
|
||||
struct scheduler_msg msg = {0, };
|
||||
|
||||
req = qdf_mem_malloc(sizeof(*req));
|
||||
if (!req) {
|
||||
tdls_err("mem allocate fail");
|
||||
return QDF_STATUS_E_NOMEM;
|
||||
}
|
||||
|
||||
status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
tdls_err("can't get vdev");
|
||||
goto error;
|
||||
}
|
||||
|
||||
req->vdev = vdev;
|
||||
req->mode = mode;
|
||||
|
||||
msg.bodyptr = req;
|
||||
msg.callback = tdls_process_cmd;
|
||||
msg.flush_callback = tdls_antenna_switch_flush_callback;
|
||||
msg.type = TDLS_CMD_ANTENNA_SWITCH;
|
||||
status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
tdls_err("post antenna switch msg fail");
|
||||
goto dec_ref;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
dec_ref:
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
||||
error:
|
||||
qdf_mem_free(req);
|
||||
return status;
|
||||
}
|
||||
|
Reference in New Issue
Block a user