Kaynağa Gözat

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
Frank Liu 7 yıl önce
ebeveyn
işleme
5ef3b6fc5f
2 değiştirilmiş dosya ile 59 ekleme ve 1 silme
  1. 14 1
      inc/wlan_cfg80211_tdls.h
  2. 45 0
      src/wlan_cfg80211_tdls.c

+ 14 - 1
inc/wlan_cfg80211_tdls.h

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

+ 45 - 0
src/wlan_cfg80211_tdls.c

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