Browse Source

qcacld-3.0: Enable/disable TSF sync feature through NL command

Enable/disable TSF sync feature through QCA_TSF_SYNC_START and
QCA_TSF_SYNC_STOP NL command. Also add support to configure
TSF sync interval through QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL
attribute.

Change-Id: If679fdf2c92848402cf1b8fcbfb669cd1cc2b861
CRs-Fixed: 3108414
Vishal Miskin 3 years ago
parent
commit
016e8e808c

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

@@ -1226,6 +1226,8 @@ struct hdd_context;
  * @vdev_id: Unique identifier assigned to the vdev
  * @event_flags: a bitmap of hdd_adapter_flags
  * @mic_work: mic work information
+ * @enable_dynamic_tsf_sync: Enable/Disable TSF sync through NL interface
+ * @dynamic_tsf_sync_interval: TSF sync interval configure through NL interface
  * @gpio_tsf_sync_work: work to sync send TSF CAP WMI command
  * @cache_sta_count: number of currently cached stations
  * @acs_complete_event: acs complete event
@@ -1393,6 +1395,8 @@ struct hdd_adapter {
 	/* spin lock for read/write timestamps */
 	qdf_spinlock_t host_target_sync_lock;
 	qdf_mc_timer_t host_target_sync_timer;
+	bool enable_dynamic_tsf_sync;
+	uint32_t dynamic_tsf_sync_interval;
 	uint64_t cur_host_time;
 	uint64_t last_host_time;
 	uint64_t last_target_time;

+ 30 - 5
core/hdd/inc/wlan_hdd_tsf.h

@@ -58,6 +58,18 @@ enum hdd_tsf_capture_state {
 	TSF_CAP_STATE
 };
 
+/**
+ * struct hdd_tsf_op_response - Store TSF sync parameters if TSF sync is active
+ * @status: TSF response status defined by enum hdd_tsf_get_state
+ * @time: TSF sync Target time. Time unit is microseconds.
+ * @soc_time: TSF sync SOC time. Time unit is microseconds.
+ */
+struct hdd_tsf_op_response {
+	enum hdd_tsf_get_state status;
+	uint64_t time;
+	uint64_t soc_time;
+};
+
 #ifdef WLAN_FEATURE_TSF
 /**
  * wlan_hdd_tsf_init() - set gpio and callbacks for
@@ -99,14 +111,14 @@ int hdd_capture_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len);
  * hdd_indicate_tsf() - return tsf to uplayer
  *
  * @adapter: pointer to adapter
- * @buf: pointer to uplayer buf
- * @len : the length of buf
+ * @tsf_op_resp: pointer to struct hdd_tsf_op_response
  *
  * This function returns tsf value to uplayer.
  *
  * Return: Describe the execute result of this routine
  */
-int hdd_indicate_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len);
+int hdd_indicate_tsf(struct hdd_adapter *adapter,
+		     struct hdd_tsf_op_response *tsf_op_resp);
 
 /**
  * wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations
@@ -147,8 +159,8 @@ static inline void wlan_hdd_tsf_deinit(struct hdd_context *hdd_ctx)
 {
 }
 
-static inline int hdd_indicate_tsf(struct hdd_adapter *adapter, uint32_t *buf,
-				int len)
+static inline int hdd_indicate_tsf(struct hdd_adapter *adapter,
+				   struct hdd_tsf_op_response *tsf_op_resp)
 {
 	return -ENOTSUPP;
 }
@@ -254,6 +266,14 @@ void hdd_capture_req_timer_expired_handler(void *arg);
  */
 bool hdd_tsf_is_tsf64_tx_set(struct hdd_context *hdd);
 
+/**
+ * hdd_update_dynamic_tsf_sync - Configure TSF mode for vdev
+ * @adapter: pointer to hdd adapter
+ *
+ * This function configures TSF mode for vdev with ini parameter
+ */
+void hdd_update_dynamic_tsf_sync(struct hdd_adapter *adapter);
+
 #ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS
 /**
  * hdd_rx_timestamp() - time stamp RX netbuf
@@ -302,6 +322,11 @@ bool hdd_tsf_is_tsf64_tx_set(struct hdd_context *hdd)
 	return FALSE;
 }
 
+static inline
+void hdd_update_dynamic_tsf_sync(struct hdd_adapter *adapter)
+{
+}
+
 static inline
 QDF_STATUS hdd_get_tsf_time(void *adapter_ctx, uint64_t input_time,
 			    uint64_t *tsf_time)

+ 1 - 0
core/hdd/src/wlan_hdd_hostapd.c

@@ -4164,6 +4164,7 @@ struct hdd_adapter *hdd_wlan_create_ap_dev(struct hdd_context *hdd_ctx,
 	qdf_mem_copy(adapter->mac_addr.bytes, mac_addr, sizeof(tSirMacAddr));
 
 	adapter->offloads_configured = false;
+	hdd_update_dynamic_tsf_sync(adapter);
 	hdd_dev_setup_destructor(dev);
 	dev->ieee80211_ptr = &adapter->wdev;
 	adapter->wdev.wiphy = hdd_ctx->wiphy;

+ 8 - 1
core/hdd/src/wlan_hdd_hostapd_wext.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -1053,6 +1054,7 @@ static int __iw_softap_get_three(struct net_device *dev,
 	int ret = 0; /* success */
 	struct hdd_context *hdd_ctx;
 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	struct hdd_tsf_op_response tsf_op_resp;
 
 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	ret = wlan_hdd_validate_context(hdd_ctx);
@@ -1065,7 +1067,12 @@ static int __iw_softap_get_three(struct net_device *dev,
 
 	switch (sub_cmd) {
 	case QCSAP_GET_TSF:
-		ret = hdd_indicate_tsf(adapter, value, 3);
+		ret = hdd_indicate_tsf(adapter, &tsf_op_resp);
+		if (!ret) {
+			value[0] = tsf_op_resp.status;
+			value[1] = tsf_op_resp.time & 0xffffffff;
+			value[2] = (tsf_op_resp.time >> 32) & 0xffffffff;
+		}
 		break;
 	default:
 		hdd_err("Invalid getparam command: %d", sub_cmd);

+ 1 - 0
core/hdd/src/wlan_hdd_main.c

@@ -6180,6 +6180,7 @@ hdd_alloc_station_adapter(struct hdd_context *hdd_ctx, tSirMacAddr mac_addr,
 	init_completion(&adapter->vdev_destroy_event);
 
 	adapter->offloads_configured = false;
+	hdd_update_dynamic_tsf_sync(adapter);
 	adapter->is_link_up_service_needed = false;
 	adapter->send_mode_change = true;
 

+ 192 - 70
core/hdd/src/wlan_hdd_tsf.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -305,6 +305,12 @@ static bool hdd_is_tsf_sync_enabled(struct hdd_context *hdd)
 	else
 		return false;
 }
+
+void hdd_update_dynamic_tsf_sync(struct hdd_adapter *adapter)
+{
+	adapter->enable_dynamic_tsf_sync =
+			hdd_is_tsf_sync_enabled(adapter->hdd_ctx);
+}
 #else
 
 static bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd)
@@ -555,64 +561,62 @@ static enum hdd_tsf_op_result hdd_capture_tsf_internal(
 }
 
 static enum hdd_tsf_op_result hdd_indicate_tsf_internal(
-	struct hdd_adapter *adapter, uint32_t *buf, int len)
+	struct hdd_adapter *adapter, struct hdd_tsf_op_response *tsf_op_resp)
 {
 	int ret;
 	struct hdd_context *hddctx;
 
-	if (!adapter || !buf) {
+	if (!adapter || !tsf_op_resp) {
 		hdd_err("invalid pointer");
 		return HDD_TSF_OP_FAIL;
 	}
 
-	if (len != 3)
-		return HDD_TSF_OP_FAIL;
-
 	hddctx = WLAN_HDD_GET_CTX(adapter);
 	if (!hddctx) {
 		hdd_err("invalid hdd context");
 		return HDD_TSF_OP_FAIL;
 	}
 
-	buf[1] = 0;
-	buf[2] = 0;
-
+	memset(tsf_op_resp, 0, sizeof(*tsf_op_resp));
 	if (!hdd_tsf_is_initialized(adapter)) {
-		buf[0] = TSF_NOT_READY;
+		tsf_op_resp->status = TSF_NOT_READY;
 		return HDD_TSF_OP_SUCC;
 	}
 
-	buf[0] = hdd_tsf_check_conn_state(adapter);
-	if (buf[0] != TSF_RETURN)
+	tsf_op_resp->status = hdd_tsf_check_conn_state(adapter);
+	if (tsf_op_resp->status != TSF_RETURN)
 		return HDD_TSF_OP_SUCC;
 
 	if (adapter->cur_target_time == 0) {
 		hdd_info("TSF value not received");
-		buf[0] = TSF_NOT_RETURNED_BY_FW;
+		tsf_op_resp->status = TSF_NOT_RETURNED_BY_FW;
 		return HDD_TSF_OP_SUCC;
 	}
 
-	buf[0] = TSF_RETURN;
-	buf[1] = (uint32_t)(adapter->cur_target_time & 0xffffffff);
-	buf[2] = (uint32_t)((adapter->cur_target_time >> 32) &
-				0xffffffff);
+	tsf_op_resp->status = TSF_RETURN;
+	tsf_op_resp->time = adapter->cur_target_time;
+	tsf_op_resp->soc_time = adapter->cur_tsf_sync_soc_time;
 
 	if (!qdf_atomic_read(&hddctx->cap_tsf_flag)) {
-		hdd_info("old: status=%u, tsf_low=%u, tsf_high=%u",
-			 buf[0], buf[1], buf[2]);
+		hdd_info("old: status=%u, tsf_time=%llu, tsf_soc_time=%llu",
+			 tsf_op_resp->status,
+			 tsf_op_resp->time,
+			 tsf_op_resp->soc_time);
 		return HDD_TSF_OP_SUCC;
 	}
 
 	ret = hdd_tsf_reset_gpio(adapter);
 	if (0 != ret) {
 		hdd_err("reset tsf gpio fail");
-		buf[0] = TSF_RESET_GPIO_FAIL;
+		tsf_op_resp->status = TSF_RESET_GPIO_FAIL;
 		return HDD_TSF_OP_SUCC;
 	}
 	hddctx->cap_tsf_context = NULL;
 	qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
-	hdd_info("get tsf cmd,status=%u, tsf_low=%u, tsf_high=%u",
-		 buf[0], buf[1], buf[2]);
+	hdd_info("get tsf cmd,status=%u, tsf_time=%llu, tsf_soc_time=%llu",
+		 tsf_op_resp->status,
+							tsf_op_resp->time,
+							tsf_op_resp->soc_time);
 
 	return HDD_TSF_OP_SUCC;
 }
@@ -681,9 +685,6 @@ enum hdd_tsf_op_result __hdd_stop_tsf_sync(struct hdd_adapter *adapter)
 		return HDD_TSF_OP_FAIL;
 	}
 
-	if (!hdd_is_tsf_sync_enabled(hdd_ctx))
-		return HDD_TSF_OP_FAIL;
-
 	if (!hdd_get_th_sync_status(adapter)) {
 		hdd_err("Host Target sync has not initialized");
 		return HDD_TSF_OP_SUCC;
@@ -1200,8 +1201,12 @@ static void hdd_update_timestamp(struct hdd_adapter *adapter)
 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last
 		 * TSF-HOST update.
 		 */
-		interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC -
-			    CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC;
+
+		if (adapter->dynamic_tsf_sync_interval)
+			interval = adapter->dynamic_tsf_sync_interval;
+		else
+			interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC -
+				    CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC;
 
 		adapter->continuous_error_count = 0;
 		adapter->continuous_cap_retry_count = 0;
@@ -1282,11 +1287,9 @@ static ssize_t __hdd_wlan_tsf_show(struct device *dev,
 
 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
 {
-	uint32_t tsf_op_resp[3];
-	struct hdd_context *hddctx;
+	struct hdd_tsf_op_response tsf_op_resp;
 
-	hddctx = WLAN_HDD_GET_CTX(adapter);
-	hdd_indicate_tsf_internal(adapter, tsf_op_resp, 3);
+	hdd_indicate_tsf_internal(adapter, &tsf_op_resp);
 	hdd_update_timestamp(adapter);
 }
 #else
@@ -1433,9 +1436,9 @@ static ssize_t __hdd_wlan_tsf_show(struct device *dev,
 
 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
 {
-	uint32_t tsf_op_resp[3];
+	struct hdd_tsf_op_response tsf_op_resp;
 
-	hdd_indicate_tsf_internal(adapter, tsf_op_resp, 3);
+	hdd_indicate_tsf_internal(adapter, &tsf_op_resp);
 	hdd_update_timestamp(adapter, tsf, 0);
 }
 #endif
@@ -1480,7 +1483,7 @@ static enum hdd_tsf_op_result hdd_tsf_sync_init(struct hdd_adapter *adapter)
 		return HDD_TSF_OP_FAIL;
 	}
 
-	if (!hdd_is_tsf_sync_enabled(hddctx)) {
+	if (!adapter->enable_dynamic_tsf_sync) {
 		hdd_err("TSF sync feature not enabled");
 		return HDD_TSF_OP_FAIL;
 	}
@@ -1606,24 +1609,124 @@ static inline int __hdd_capture_tsf(struct hdd_adapter *adapter,
 	return 0;
 }
 
-static inline int __hdd_indicate_tsf(struct hdd_adapter *adapter,
-				     uint32_t *buf, int len)
+/**
+ * hdd_handle_tsf_dynamic_start()
+ * @adapter: Adapter pointer
+ * @attr: TSF sync interval from NL interface
+ *
+ * This function enables TSF sync if capture mode is Dynamic set from ini
+ *
+ * Return: 0 for success or non-zero negative failure code
+ */
+static int hdd_handle_tsf_dynamic_start(struct hdd_adapter *adapter,
+					struct nlattr *attr)
 {
-	if (!adapter || !buf) {
-		hdd_err("invalid pointer");
+	struct hdd_context *hdd_ctx;
+	uint32_t dynamic_tsf_sync_interval = 0;
+
+	if (!adapter)
 		return -EINVAL;
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	if (wlan_hdd_validate_context(hdd_ctx))
+		return -EINVAL;
+
+	if (attr)
+		dynamic_tsf_sync_interval = nla_get_u32(attr);
+
+	if (adapter->enable_dynamic_tsf_sync) {
+		if (dynamic_tsf_sync_interval ==
+		    adapter->dynamic_tsf_sync_interval) {
+			return -EALREADY;
+		}
+		adapter->dynamic_tsf_sync_interval =
+			 dynamic_tsf_sync_interval;
+		return 0;
 	}
 
-	if (len != 3)
+	adapter->dynamic_tsf_sync_interval = dynamic_tsf_sync_interval;
+	adapter->enable_dynamic_tsf_sync = true;
+
+	return hdd_start_tsf_sync(adapter);
+}
+
+/**
+ * hdd_handle_tsf_dynamic_stop()
+ * @adapter: Adapter pointer
+ *
+ * This function disable TSF sync if capture mode is Dynamic set from ini
+ *
+ * Return: 0 for success or non-zero negative failure code
+ */
+static int hdd_handle_tsf_dynamic_stop(struct hdd_adapter *adapter)
+{
+	struct hdd_context *hdd_ctx;
+
+	if (!adapter)
 		return -EINVAL;
 
-	buf[0] = TSF_DISABLED_BY_TSFPLUS;
-	buf[1] = 0;
-	buf[2] = 0;
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	if (wlan_hdd_validate_context(hdd_ctx))
+		return -EINVAL;
 
-	return 0;
+	if (!adapter->enable_dynamic_tsf_sync)
+		return -EALREADY;
+
+	adapter->enable_dynamic_tsf_sync = false;
+	adapter->dynamic_tsf_sync_interval = 0;
+	return hdd_stop_tsf_sync(adapter);
 }
 
+#if defined(WLAN_FEATURE_TSF_TIMER_SYNC)
+static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter,
+						 struct hdd_tsf_op_response
+								*tsf_op_resp)
+{
+	if (!adapter || !tsf_op_resp) {
+		hdd_err("invalid pointer");
+		return HDD_TSF_OP_FAIL;
+	}
+
+	memset(tsf_op_resp, 0, sizeof(*tsf_op_resp));
+	if (!hdd_tsf_is_initialized(adapter)) {
+		tsf_op_resp->status = TSF_NOT_READY;
+		return HDD_TSF_OP_SUCC;
+	}
+
+	tsf_op_resp->status = hdd_tsf_check_conn_state(adapter);
+	if (tsf_op_resp->status != TSF_RETURN)
+		return HDD_TSF_OP_SUCC;
+
+	if (adapter->last_target_time == 0) {
+		hdd_info("TSF value not received");
+		tsf_op_resp->status = TSF_NOT_RETURNED_BY_FW;
+		return HDD_TSF_OP_SUCC;
+	}
+
+	tsf_op_resp->time = adapter->last_target_time;
+	tsf_op_resp->soc_time = adapter->last_tsf_sync_soc_time;
+
+	return HDD_TSF_OP_SUCC;
+}
+
+#else
+static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter,
+						 struct hdd_tsf_op_response
+								*tsf_op_resp)
+{
+	if (!adapter || !tsf_op_resp) {
+		hdd_err("invalid pointer");
+		return HDD_TSF_OP_FAIL;
+	}
+
+	tsf_op_resp->status = TSF_DISABLED_BY_TSFPLUS;
+	tsf_op_resp->time = 0;
+	tsf_op_resp->soc_time = 0;
+
+	return HDD_TSF_OP_SUCC;
+}
+#endif
+
 #ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS
 #ifdef CONFIG_HL_SUPPORT
 static inline
@@ -2052,11 +2155,11 @@ static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
 {
 }
 
-static inline int __hdd_indicate_tsf(struct hdd_adapter *adapter,
-				     uint32_t *buf, int len)
+static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter,
+						 struct hdd_tsf_op_response
+								*tsf_op_resp)
 {
-	return (hdd_indicate_tsf_internal(adapter, buf, len) ==
-		HDD_TSF_OP_SUCC) ? 0 : -EINVAL;
+	return hdd_indicate_tsf_internal(adapter, tsf_op_resp);
 }
 
 static inline int __hdd_capture_tsf(struct hdd_adapter *adapter,
@@ -2078,6 +2181,16 @@ enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
 	return HDD_TSF_OP_SUCC;
 }
 
+static inline int hdd_handle_tsf_dynamic_start(struct hdd_adapter *adapter,
+					       struct nlattr *attr)
+{
+	return -ENOTSUPP;
+}
+
+static inline int hdd_handle_tsf_dynamic_stop(struct hdd_adapter *adapter)
+{
+	return -ENOTSUPP;
+}
 #endif /* WLAN_FEATURE_TSF_PLUS */
 
 int hdd_capture_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len)
@@ -2085,9 +2198,23 @@ int hdd_capture_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len)
 	return __hdd_capture_tsf(adapter, buf, len);
 }
 
-int hdd_indicate_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len)
+int hdd_indicate_tsf(struct hdd_adapter *adapter,
+		     struct hdd_tsf_op_response *tsf_op_resp)
 {
-	return __hdd_indicate_tsf(adapter, buf, len);
+	if (__hdd_indicate_tsf(adapter, tsf_op_resp) == HDD_TSF_OP_FAIL)
+		return -EINVAL;
+
+	switch (tsf_op_resp->status) {
+	case TSF_RETURN:
+		return 0;
+	case TSF_NOT_RETURNED_BY_FW:
+		return -EINPROGRESS;
+	case TSF_STA_NOT_CONNECTED_NO_TSF:
+	case TSF_SAP_NOT_STARTED_NO_TSF:
+		return -EPERM;
+	default:
+		return -EINVAL;
+	}
 }
 
 #ifdef WLAN_FEATURE_TSF_PTP
@@ -2501,6 +2628,7 @@ int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf)
 
 const struct nla_policy tsf_policy[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1] = {
 	[QCA_WLAN_VENDOR_ATTR_TSF_CMD] = {.type = NLA_U32},
+	[QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL] = {.type = NLA_U32},
 };
 
 /**
@@ -2523,9 +2651,12 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1];
+	struct hdd_tsf_op_response tsf_op_resp;
+	struct nlattr *attr;
+	enum hdd_tsf_get_state value;
 	int status, ret;
 	struct sk_buff *reply_skb;
-	uint32_t tsf_op_resp[3] = {0}, tsf_cmd;
+	uint32_t tsf_cmd;
 
 	hdd_enter_dev(wdev->netdev);
 
@@ -2554,8 +2685,8 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
 		goto end;
 
 	if (tsf_cmd == QCA_TSF_CAPTURE || tsf_cmd == QCA_TSF_SYNC_GET) {
-		hdd_capture_tsf(adapter, tsf_op_resp, 1);
-		switch (tsf_op_resp[0]) {
+		hdd_capture_tsf(adapter, &value, 1);
+		switch (value) {
 		case TSF_RETURN:
 			status = 0;
 			break;
@@ -2571,7 +2702,13 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
 			status = -EINVAL;
 			break;
 		}
+	} else if (tsf_cmd == QCA_TSF_SYNC_START) {
+		attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL];
+		status = hdd_handle_tsf_dynamic_start(adapter, attr);
+	} else if (tsf_cmd == QCA_TSF_SYNC_STOP) {
+		status = hdd_handle_tsf_dynamic_stop(adapter);
 	}
+
 	if (status < 0)
 		goto end;
 
@@ -2585,22 +2722,7 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
 	}
 
 	if (tsf_cmd == QCA_TSF_GET || tsf_cmd == QCA_TSF_SYNC_GET) {
-		hdd_indicate_tsf(adapter, tsf_op_resp, 3);
-		switch (tsf_op_resp[0]) {
-		case TSF_RETURN:
-			status = 0;
-			break;
-		case TSF_NOT_RETURNED_BY_FW:
-			status = -EINPROGRESS;
-			break;
-		case TSF_STA_NOT_CONNECTED_NO_TSF:
-		case TSF_SAP_NOT_STARTED_NO_TSF:
-			status = -EPERM;
-			break;
-		default:
-			status = -EINVAL;
-			break;
-		}
+		status = hdd_indicate_tsf(adapter, &tsf_op_resp);
 		if (status != 0)
 			goto end;
 
@@ -2615,10 +2737,10 @@ static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
 		}
 		if (hdd_wlan_nla_put_u64(reply_skb,
 				QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE,
-				adapter->cur_target_time) ||
+				tsf_op_resp.time) ||
 		    hdd_wlan_nla_put_u64(reply_skb,
 				QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE,
-				adapter->cur_tsf_sync_soc_time)) {
+				tsf_op_resp.soc_time)) {
 			hdd_err("nla put fail");
 			kfree_skb(reply_skb);
 			status = -EINVAL;

+ 7 - 1
core/hdd/src/wlan_hdd_wext.c

@@ -5091,6 +5091,7 @@ static int __iw_setnone_get_threeint(struct net_device *dev,
 	uint32_t *value = (int *)extra;
 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	struct hdd_tsf_op_response tsf_op_resp;
 
 	hdd_enter_dev(dev);
 	ret = wlan_hdd_validate_context(hdd_ctx);
@@ -5104,7 +5105,12 @@ static int __iw_setnone_get_threeint(struct net_device *dev,
 	hdd_debug("param = %d", value[0]);
 	switch (value[0]) {
 	case WE_GET_TSF:
-		ret = hdd_indicate_tsf(adapter, value, 3);
+		ret = hdd_indicate_tsf(adapter, &tsf_op_resp);
+		if (!ret) {
+			value[0] = tsf_op_resp.status;
+			value[1] = tsf_op_resp.time & 0xffffffff;
+			value[2] = (tsf_op_resp.time >> 32) & 0xffffffff;
+		}
 		break;
 	default:
 		hdd_err("Invalid IOCTL get_value command %d", value[0]);