qcacld-3.0: get tsf from fw

qcacld-2.0 to qcacld-3.0 propagation

Get tsf from fw. Provide ioctl interface cap_tsf/get_tsf.
Driver issue wmi cmd to fw to realize capture/get.
It can be used in station and softap mode. For sta, getting
tsf from connected ap. For softap, it will generate tsf by-
self

Change-Id: I00d30882bce2f49ee3de3fa189e094c04c0d9943
CRs-Fixed: 817527
diff --git a/Kbuild b/Kbuild
index 1031b35..11eed09 100755
--- a/Kbuild
+++ b/Kbuild
@@ -377,6 +377,10 @@
 HDD_OBJS +=	$(HDD_SRC_DIR)/wlan_hdd_tdls.o
 endif
 
+ifeq ($(CONFIG_WLAN_SYNC_TSF),y)
+HDD_OBJS +=	$(HDD_SRC_DIR)/wlan_hdd_tsf.o
+endif
+
 ifeq ($(CONFIG_MPC_UT_FRAMEWORK),y)
 HDD_OBJS +=	$(HDD_SRC_DIR)/wlan_hdd_conc_ut.o
 endif
@@ -1360,6 +1364,10 @@
 CDEFINES += -DLINUX_QCMBR
 endif
 
+# Enable featue sync tsf between multi devices
+ifeq ($(CONFIG_WLAN_SYNC_TSF), y)
+CDEFINES += -DWLAN_FEATURE_TSF
+endif
 
 # Enable full rx re-order offload for adrastea
 ifeq (y, $(filter y, $(CONFIG_CNSS_ADRASTEA) $(CONFIG_ICNSS)))
diff --git a/Kconfig b/Kconfig
index 7155ea2..39b64ed 100644
--- a/Kconfig
+++ b/Kconfig
@@ -107,6 +107,10 @@
 	bool "Enable RX wake lock feature"
 	default n
 
+config WLAN_SYNC_TSF
+	bool "Enable QCOM sync multi devices tsf feature"
+	default n
+
 config FEATURE_LFR_SUBNET_DETECTION
 	bool "Enable LFR Subnet Change Detection"
 	default n
diff --git a/core/hdd/inc/qc_sap_ioctl.h b/core/hdd/inc/qc_sap_ioctl.h
index 5a1bfbe..cede160 100644
--- a/core/hdd/inc/qc_sap_ioctl.h
+++ b/core/hdd/inc/qc_sap_ioctl.h
@@ -131,42 +131,43 @@
  *     (regardless of the incorrect comment in wireless.h!)
  */
 
-#define QCSAP_IOCTL_SETPARAM          (SIOCIWFIRSTPRIV+0)
-#define QCSAP_IOCTL_GETPARAM          (SIOCIWFIRSTPRIV+1)
+#define QCSAP_IOCTL_SETPARAM          (SIOCIWFIRSTPRIV + 0)
+#define QCSAP_IOCTL_GETPARAM          (SIOCIWFIRSTPRIV + 1)
 /* (SIOCIWFIRSTPRIV+2) is unused */
-/* (SIOCIWFIRSTPRIV+3) is unused */
-#define QCSAP_IOCTL_GET_STAWPAIE      (SIOCIWFIRSTPRIV+4)
-#define QCSAP_IOCTL_SETWPAIE          (SIOCIWFIRSTPRIV+5)
-#define QCSAP_IOCTL_STOPBSS           (SIOCIWFIRSTPRIV+6)
-#define QCSAP_IOCTL_VERSION           (SIOCIWFIRSTPRIV+7)
-#define QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES       (SIOCIWFIRSTPRIV+8)
-#define QCSAP_IOCTL_GET_CHANNEL       (SIOCIWFIRSTPRIV+9)
-#define QCSAP_IOCTL_ASSOC_STA_MACADDR (SIOCIWFIRSTPRIV+10)
-#define QCSAP_IOCTL_DISASSOC_STA      (SIOCIWFIRSTPRIV+11)
+#define QCSAP_IOCTL_SET_NONE_GET_THREE (SIOCIWFIRSTPRIV + 3)
+#define WE_GET_TSF 1
+#define QCSAP_IOCTL_GET_STAWPAIE      (SIOCIWFIRSTPRIV + 4)
+#define QCSAP_IOCTL_SETWPAIE          (SIOCIWFIRSTPRIV + 5)
+#define QCSAP_IOCTL_STOPBSS           (SIOCIWFIRSTPRIV + 6)
+#define QCSAP_IOCTL_VERSION           (SIOCIWFIRSTPRIV + 7)
+#define QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES       (SIOCIWFIRSTPRIV + 8)
+#define QCSAP_IOCTL_GET_CHANNEL       (SIOCIWFIRSTPRIV + 9)
+#define QCSAP_IOCTL_ASSOC_STA_MACADDR (SIOCIWFIRSTPRIV + 10)
+#define QCSAP_IOCTL_DISASSOC_STA      (SIOCIWFIRSTPRIV + 11)
 /* (SIOCIWFIRSTPRIV+12) is unused */
 /* Private ioctls and their sub-ioctls */
 #define QCSAP_PRIV_GET_CHAR_SET_NONE   (SIOCIWFIRSTPRIV + 13)
 #define QCSAP_GET_STATS 1
 #define QCSAP_LIST_FW_PROFILE 2
-#define QCSAP_IOCTL_CLR_STATS         (SIOCIWFIRSTPRIV+14)
+#define QCSAP_IOCTL_CLR_STATS         (SIOCIWFIRSTPRIV + 14)
 
-#define QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV+15)
+#define QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV + 15)
 #define WE_SET_WLAN_DBG 1
 #define WE_SET_DP_TRACE 2
 #define WE_SET_SAP_CHANNELS  3
-#define QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV+16)
+#define QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV + 16)
 #define WE_UNIT_TEST_CMD   7
-#define QCSAP_IOCTL_SET_CHANNEL_RANGE (SIOCIWFIRSTPRIV+17)
+#define QCSAP_IOCTL_SET_CHANNEL_RANGE (SIOCIWFIRSTPRIV + 17)
 
 #define WE_P2P_NOA_CMD  2
 
-#define QCSAP_IOCTL_MODIFY_ACL          (SIOCIWFIRSTPRIV+18)
-#define QCSAP_IOCTL_GET_CHANNEL_LIST    (SIOCIWFIRSTPRIV+19)
-#define QCSAP_IOCTL_SET_TX_POWER        (SIOCIWFIRSTPRIV+20)
-#define QCSAP_IOCTL_GET_STA_INFO        (SIOCIWFIRSTPRIV+21)
-#define QCSAP_IOCTL_SET_MAX_TX_POWER    (SIOCIWFIRSTPRIV+22)
-#define QCSAP_IOCTL_GET_INI_CFG         (SIOCIWFIRSTPRIV+25)
-#define QCSAP_IOCTL_SET_INI_CFG         (SIOCIWFIRSTPRIV+26)
+#define QCSAP_IOCTL_MODIFY_ACL          (SIOCIWFIRSTPRIV + 18)
+#define QCSAP_IOCTL_GET_CHANNEL_LIST    (SIOCIWFIRSTPRIV + 19)
+#define QCSAP_IOCTL_SET_TX_POWER        (SIOCIWFIRSTPRIV + 20)
+#define QCSAP_IOCTL_GET_STA_INFO        (SIOCIWFIRSTPRIV + 21)
+#define QCSAP_IOCTL_SET_MAX_TX_POWER    (SIOCIWFIRSTPRIV + 22)
+#define QCSAP_IOCTL_GET_INI_CFG         (SIOCIWFIRSTPRIV + 25)
+#define QCSAP_IOCTL_SET_INI_CFG         (SIOCIWFIRSTPRIV + 26)
 #define QCSAP_IOCTL_SET_TWO_INT_GET_NONE (SIOCIWFIRSTPRIV + 28)
 #ifdef DEBUG
 #define QCSAP_IOCTL_SET_FW_CRASH_INJECT 1
@@ -241,7 +242,9 @@
 	QCASAP_CLEAR_STATS,
 	QCASAP_SET_RADAR_DBG,
 	QCSAP_GET_FW_PROFILE_DATA,
-	QCSAP_START_FW_PROFILING
+	QCSAP_START_FW_PROFILING,
+	QCSAP_CAP_TSF,
+	QCSAP_GET_TSF,
 };
 
 int iw_softap_get_channel_list(struct net_device *dev,
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index 39fe7e1..ab3873a 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -57,6 +57,7 @@
 #ifdef FEATURE_WLAN_TDLS
 #include "wlan_hdd_tdls.h"
 #endif
+#include "wlan_hdd_tsf.h"
 #include "wlan_hdd_cfg80211.h"
 #include <qdf_defer.h>
 #ifdef WLAN_FEATURE_MBSSID
@@ -940,6 +941,14 @@
 		hdd_ap_ctx_t ap;
 	} sessionCtx;
 
+#ifdef WLAN_FEATURE_TSF
+	/* tsf value received from firmware */
+	uint32_t tsf_low;
+	uint32_t tsf_high;
+	/* TSF capture state */
+	enum hdd_tsf_capture_state tsf_state;
+#endif
+
 	hdd_cfg80211_state_t cfg80211State;
 
 #ifdef WLAN_FEATURE_PACKET_FILTERING
diff --git a/core/hdd/inc/wlan_hdd_tsf.h b/core/hdd/inc/wlan_hdd_tsf.h
new file mode 100644
index 0000000..f251327
--- /dev/null
+++ b/core/hdd/inc/wlan_hdd_tsf.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#if !defined WLAN_HDD_TSF_H
+#define WLAN_HDD_TSF_H
+
+/**
+ * enum hdd_tsf_get_state - status of get tsf action
+ * @TSF_RETURN:                   get tsf
+ * @TSF_STA_NOT_CONNECTED_NO_TSF: sta not connected to ap
+ * @TSF_NOT_RETURNED_BY_FW:       fw not returned tsf
+ * @TSF_CURRENT_IN_CAP_STATE:     driver in capture state
+ * @TSF_CAPTURE_FAIL:             capture fail
+ * @TSF_GET_FAIL:                 get fail
+ * @TSF_RESET_GPIO_FAIL:          GPIO reset fail
+ * @TSF_SAP_NOT_STARTED_NO_TSF    SAP not started
+ */
+enum hdd_tsf_get_state {
+	TSF_RETURN = 0,
+	TSF_STA_NOT_CONNECTED_NO_TSF,
+	TSF_NOT_RETURNED_BY_FW,
+	TSF_CURRENT_IN_CAP_STATE,
+	TSF_CAPTURE_FAIL,
+	TSF_GET_FAIL,
+	TSF_RESET_GPIO_FAIL,
+	TSF_SAP_NOT_STARTED_NO_TSF
+};
+
+/**
+ * enum hdd_tsf_capture_state - status of capture
+ * @TSF_IDLE:      idle
+ * @TSF_CAP_STATE: current is in capture state
+ */
+enum hdd_tsf_capture_state {
+	TSF_IDLE = 0,
+	TSF_CAP_STATE
+};
+
+#ifdef WLAN_FEATURE_TSF
+void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx);
+int hdd_capture_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len);
+int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len);
+#else
+static inline void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx)
+{
+	return;
+}
+
+static inline int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf,
+				int len)
+{
+	return -ENOTSUPP;
+}
+
+static inline int
+hdd_capture_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len)
+{
+	return -ENOTSUPP;
+}
+#endif
+
+#endif
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index 3e5e640..597d512 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/core/hdd/src/wlan_hdd_hostapd.c
@@ -75,6 +75,7 @@
 #include "qdf_trace.h"
 #include "wlan_hdd_cfg.h"
 #include "cds_concurrency.h"
+#include "wlan_hdd_tsf.h"
 #include "wlan_hdd_green_ap.h"
 
 #define    IS_UP(_dev) \
@@ -3011,6 +3012,66 @@
 	return ret;
 }
 
+/**
+ * __iw_softap_get_three() - return three value to upper layer.
+ * @dev: pointer of net_device of this wireless card
+ * @info: meta data about Request sent
+ * @wrqu: include request info
+ * @extra: buf used for in/out
+ *
+ * Return: execute result
+ */
+static int __iw_softap_get_three(struct net_device *dev,
+					struct iw_request_info *info,
+					union iwreq_data *wrqu, char *extra)
+{
+	uint32_t *value = (uint32_t *)extra;
+	uint32_t sub_cmd = value[0];
+	int ret = 0; /* success */
+	struct hdd_context_s *hdd_ctx;
+	struct hdd_adapter_s *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret != 0)
+		return ret;
+
+	switch (sub_cmd) {
+	case QCSAP_GET_TSF:
+		ret = hdd_indicate_tsf(adapter, value, 3);
+		break;
+	default:
+		hdd_err(FL("Invalid getparam command %d"), sub_cmd);
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+
+/**
+ * iw_softap_get_three() - return three value to upper layer.
+ *
+ * @dev: pointer of net_device of this wireless card
+ * @info: meta data about Request sent
+ * @wrqu: include request info
+ * @extra: buf used for in/Output
+ *
+ * Return: execute result
+ */
+static int iw_softap_get_three(struct net_device *dev,
+					struct iw_request_info *info,
+					union iwreq_data *wrqu, char *extra)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __iw_softap_get_three(dev, info, wrqu, extra);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
+
 int
 static iw_softap_setparam(struct net_device *dev,
 			  struct iw_request_info *info,
@@ -3211,6 +3272,9 @@
 					     VDEV_CMD);
 		break;
 	}
+	case QCSAP_CAP_TSF:
+		ret = hdd_capture_tsf(pHostapdAdapter, (uint32_t *)value, 1);
+		break;
 	case QCASAP_GET_TEMP_CMD:
 	{
 		hddLog(LOG1, "QCASAP_GET_TEMP_CMD");
@@ -5822,6 +5886,15 @@
 		QCASAP_NSS_CMD, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 		"get_nss"
 	}, {
+		QCSAP_CAP_TSF, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+		"cap_tsf"
+	}, {
+		QCSAP_IOCTL_SET_NONE_GET_THREE, 0, IW_PRIV_TYPE_INT |
+		IW_PRIV_SIZE_FIXED | 3,    ""
+	}, {
+		QCSAP_GET_TSF, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3,
+		"get_tsf"
+	}, {
 		QCASAP_GET_TEMP_CMD, 0,
 		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_temp"
 	}, {
@@ -5997,6 +6070,8 @@
 	[QCSAP_IOCTL_SETPARAM - SIOCIWFIRSTPRIV] = iw_softap_setparam,
 	/* get priv ioctl */
 	[QCSAP_IOCTL_GETPARAM - SIOCIWFIRSTPRIV] = iw_softap_getparam,
+	[QCSAP_IOCTL_SET_NONE_GET_THREE - SIOCIWFIRSTPRIV] =
+							iw_softap_get_three,
 	/* get station genIE */
 	[QCSAP_IOCTL_GET_STAWPAIE - SIOCIWFIRSTPRIV] = iw_get_genie,
 	[QCSAP_IOCTL_SETWPAIE - SIOCIWFIRSTPRIV] = iw_softap_setwpsie,
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index acf6f9d..730ee4e 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -101,6 +101,7 @@
 #include "hif.h"
 #include "wma.h"
 #include "cds_concurrency.h"
+#include "wlan_hdd_tsf.h"
 #include "wlan_hdd_green_ap.h"
 #include "platform_icnss.h"
 #include "bmi.h"
@@ -5963,7 +5964,7 @@
 				hdd_rssi_threshold_breached);
 
 	hdd_cfg80211_link_layer_stats_init(hdd_ctx);
-
+	wlan_hdd_tsf_init(hdd_ctx);
 	wlan_hdd_send_all_scan_intf_info(hdd_ctx);
 	wlan_hdd_send_version_pkg(hdd_ctx->target_fw_version,
 				  hdd_ctx->target_hw_version,
diff --git a/core/hdd/src/wlan_hdd_tsf.c b/core/hdd/src/wlan_hdd_tsf.c
new file mode 100644
index 0000000..2563a94
--- /dev/null
+++ b/core/hdd/src/wlan_hdd_tsf.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+/**
+ * wlan_hdd_tsf.c - WLAN Host Device Driver tsf related implementation
+ */
+
+#include "wlan_hdd_main.h"
+#include "wma_api.h"
+
+/**
+ * hdd_capture_tsf() - capture tsf
+ * @adapter: pointer to adapter
+ * @buf: pointer to uplayer buf
+ * @len : the length of buf
+ *
+ * This function returns tsf value to uplayer.
+ *
+ * Return: 0 for success or non-zero negative failure code
+ */
+int hdd_capture_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len)
+{
+	int ret = 0;
+	hdd_station_ctx_t *hdd_sta_ctx;
+
+	if (adapter == NULL || buf == NULL) {
+		hdd_err(FL("invalid pointer"));
+		return -EINVAL;
+	}
+	if (len != 1)
+		return -EINVAL;
+
+	/* Reset TSF value for new capture */
+	adapter->tsf_high = 0;
+	adapter->tsf_low = 0;
+
+	if (adapter->device_mode == QDF_STA_MODE ||
+		adapter->device_mode == QDF_P2P_CLIENT_MODE) {
+		hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+		if (hdd_sta_ctx->conn_info.connState !=
+			eConnectionState_Associated) {
+
+			hdd_err(FL("failed to cap tsf, not connect with ap"));
+			buf[0] = TSF_STA_NOT_CONNECTED_NO_TSF;
+			return ret;
+		}
+	}
+	if ((adapter->device_mode == QDF_SAP_MODE ||
+		adapter->device_mode == QDF_P2P_GO_MODE) &&
+		!(test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags))) {
+		hdd_err(FL("Soft AP / P2p GO not beaconing"));
+		buf[0] = TSF_SAP_NOT_STARTED_NO_TSF;
+		return ret;
+	}
+	if (adapter->tsf_state == TSF_CAP_STATE) {
+		hdd_err(FL("current in capture state, pls reset"));
+			buf[0] = TSF_CURRENT_IN_CAP_STATE;
+	} else {
+		hdd_info(FL("Send TSF capture to FW"));
+		buf[0] = TSF_RETURN;
+		adapter->tsf_state = TSF_CAP_STATE;
+		ret = wma_cli_set_command((int)adapter->sessionId,
+				(int)GEN_PARAM_CAPTURE_TSF,
+				adapter->sessionId,
+				GEN_CMD);
+
+		if (ret != QDF_STATUS_SUCCESS) {
+			hdd_err(FL("capture fail"));
+			buf[0] = TSF_CAPTURE_FAIL;
+			adapter->tsf_state = TSF_IDLE;
+		}
+	}
+	return ret;
+}
+
+/**
+ * hdd_indicate_tsf() - return tsf to uplayer
+ * @adapter: pointer to adapter
+ * @buf: pointer to uplayer buf
+ * @len : the length of buf
+ *
+ * This function returns tsf value to upper layer.
+ *
+ * Return: 0 for success or non-zero negative failure code
+ */
+int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len)
+{
+	int ret = 0;
+	hdd_station_ctx_t *hdd_sta_ctx;
+
+	if (adapter == NULL || buf == NULL) {
+		hdd_err(FL("invalid pointer"));
+		return -EINVAL;
+	}
+
+	if (len != 3)
+		return -EINVAL;
+
+	buf[1] = 0;
+	buf[2] = 0;
+	if (adapter->device_mode == QDF_STA_MODE ||
+		adapter->device_mode == QDF_P2P_CLIENT_MODE) {
+		hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+		if (hdd_sta_ctx->conn_info.connState !=
+			eConnectionState_Associated) {
+
+			hdd_info(FL("fail to get tsf, sta in disconnected"));
+			buf[0] = TSF_STA_NOT_CONNECTED_NO_TSF;
+			return ret;
+		}
+	}
+	if ((adapter->device_mode == QDF_SAP_MODE ||
+		adapter->device_mode == QDF_P2P_GO_MODE) &&
+		!(test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags))) {
+		hdd_err(FL("Soft AP / P2p GO not beaconing"));
+		buf[0] = TSF_SAP_NOT_STARTED_NO_TSF;
+		return ret;
+	}
+	if (adapter->tsf_high == 0 && adapter->tsf_low == 0) {
+		hdd_info(FL("TSF value not received"));
+		buf[0] = TSF_NOT_RETURNED_BY_FW;
+	} else {
+		buf[0] = TSF_RETURN;
+		buf[1] = adapter->tsf_low;
+		buf[2] = adapter->tsf_high;
+		adapter->tsf_state = TSF_IDLE;
+
+		ret = wma_cli_set_command((int)adapter->sessionId,
+				(int)GEN_PARAM_RESET_TSF_GPIO,
+				adapter->sessionId,
+				GEN_CMD);
+
+		if (0 != ret) {
+			hdd_err(FL("tsf get fail "));
+			buf[0] = TSF_RESET_GPIO_FAIL;
+		}
+		hdd_info(FL("get tsf cmd,status=%u, tsf_low=%u, tsf_high=%u"),
+			buf[0], buf[1], buf[2]);
+	}
+	return ret;
+}
+
+/**
+ * hdd_get_tsf_cb() - handle tsf callback
+ * @pcb_cxt: pointer to the hdd_contex
+ * @ptsf: pointer to struct stsf
+ *
+ * This function handle the event that reported by firmware at first.
+ * The event contains the vdev_id, current tsf value of this vdev,
+ * tsf value is 64bits, discripted in two varaible tsf_low and tsf_high.
+ * These two values each is uint32.
+ *
+ * Return: 0 for success or non-zero negative failure code
+ */
+static int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf)
+{
+	struct hdd_context_s *hddctx;
+	struct hdd_adapter_s *adapter;
+	int status;
+
+	if (pcb_cxt == NULL || ptsf == NULL) {
+		hdd_err(FL("HDD context is not valid"));
+			return -EINVAL;
+	}
+
+	hddctx = (struct hdd_context_s *)pcb_cxt;
+	status = wlan_hdd_validate_context(hddctx);
+	if (0 != status) {
+		hdd_err(FL("hdd context is not valid"));
+		return -EINVAL;
+	}
+
+	adapter = hdd_get_adapter_by_vdev(hddctx, ptsf->vdev_id);
+
+	if (NULL == adapter) {
+		hdd_err(FL("failed to find adapter"));
+		return -EINVAL;
+	}
+
+	hdd_info(FL("tsf cb handle event, device_mode is %d"),
+		adapter->device_mode);
+
+	adapter->tsf_low = ptsf->tsf_low;
+	adapter->tsf_high = ptsf->tsf_high;
+
+	hdd_info(FL("hdd_get_tsf_cb sta=%u, tsf_low=%u, tsf_high=%u"),
+		ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high);
+	return 0;
+}
+
+/**
+ * wlan_hdd_tsf_init() - set callback to handle tsf value.
+ * @hdd_ctx: pointer to the struct hdd_context_s
+ *
+ * This function set the callback to sme module, the callback will be
+ * called when a tsf event is reported by firmware
+ *
+ * Return: none
+ */
+void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx)
+{
+	sme_set_tsfcb(hdd_ctx->hHal, hdd_get_tsf_cb, hdd_ctx);
+}
diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c
index f8f4137..b88b01b 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -80,6 +80,7 @@
 #include "sme_power_save_api.h"
 #include "cds_concurrency.h"
 #include "wlan_hdd_conc_ut.h"
+#include "wlan_hdd_tsf.h"
 #include "wlan_hdd_ocb.h"
 #include "wlan_hdd_napi.h"
 #include "cdp_txrx_flow_ctrl_legacy.h"
@@ -273,6 +274,7 @@
 #define WE_GET_GTX_MINTPC               53
 #define WE_GET_GTX_BWMASK               54
 #define WE_GET_TEMPERATURE              56
+#define WE_CAP_TSF                      58
 
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_INT_GET_INT     (SIOCIWFIRSTPRIV + 2)
@@ -383,7 +385,8 @@
 /* (SIOCIWFIRSTPRIV + 10) is currently unused */
 /* (SIOCIWFIRSTPRIV + 12) is currently unused */
 /* (SIOCIWFIRSTPRIV + 14) is currently unused */
-/* (SIOCIWFIRSTPRIV + 15) is currently unused */
+#define WLAN_PRIV_SET_NONE_GET_THREE_INT   (SIOCIWFIRSTPRIV + 15)
+#define WE_GET_TSF      1
 /* (SIOCIWFIRSTPRIV + 16) is currently unused */
 /* (SIOCIWFIRSTPRIV + 17) is currently unused */
 /* (SIOCIWFIRSTPRIV + 19) is currently unused */
@@ -6299,6 +6302,65 @@
 }
 
 /**
+ * __iw_setnone_get_threeint() - return three value to up layer.
+ *
+ * @dev: pointer of net_device of this wireless card
+ * @info: meta data about Request sent
+ * @wrqu: include request info
+ * @extra: buf used for in/Output
+ *
+ * Return: execute result
+ */
+static int __iw_setnone_get_threeint(struct net_device *dev,
+					struct iw_request_info *info,
+					union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0; /* success */
+	uint32_t *value = (int *)extra;
+	hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+
+	ENTER_DEV(dev);
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (0 != ret)
+		return ret;
+
+	hdd_info(FL("param = %d"), value[0]);
+	switch (value[0]) {
+	case WE_GET_TSF:
+		ret = hdd_indicate_tsf(adapter, value, 3);
+		break;
+	default:
+		hdd_err("Invalid IOCTL get_value command %d", value[0]);
+		break;
+	}
+	return ret;
+}
+
+/**
+ * iw_setnone_get_threeint() - return three value to up layer.
+ *
+ * @dev: pointer of net_device of this wireless card
+ * @info: meta data about Request sent
+ * @wrqu: include request info
+ * @extra: buf used for in/Output
+ *
+ * Return: execute result
+ */
+static int iw_setnone_get_threeint(struct net_device *dev,
+					struct iw_request_info *info,
+					union iwreq_data *wrqu, char *extra)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __iw_setnone_get_threeint(dev, info, wrqu, extra);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
+
+/**
  * iw_setchar_getnone() - Generic "set string" private ioctl handler
  * @dev: device upon which the ioctl was received
  * @info: ioctl request information
@@ -6914,7 +6976,9 @@
 					     QPOWER_CMD);
 		break;
 	}
-
+	case WE_CAP_TSF:
+		ret = hdd_capture_tsf(pAdapter, (uint32_t *)value, 1);
+		break;
 	case WE_GET_TEMPERATURE:
 	{
 		hddLog(QDF_TRACE_LEVEL_INFO, "WE_GET_TEMPERATURE");
@@ -9809,6 +9873,8 @@
 	[WLAN_PRIV_SET_NONE_GET_NONE - SIOCIWFIRSTPRIV] = iw_setnone_getnone,   /* action priv ioctl */
 	[WLAN_PRIV_SET_VAR_INT_GET_NONE - SIOCIWFIRSTPRIV] =
 		iw_hdd_set_var_ints_getnone,
+	[WLAN_PRIV_SET_NONE_GET_THREE_INT - SIOCIWFIRSTPRIV] =
+							iw_setnone_get_threeint,
 	[WLAN_PRIV_ADD_TSPEC - SIOCIWFIRSTPRIV] = iw_add_tspec,
 	[WLAN_PRIV_DEL_TSPEC - SIOCIWFIRSTPRIV] = iw_del_tspec,
 	[WLAN_PRIV_GET_TSPEC - SIOCIWFIRSTPRIV] = iw_get_tspec,
@@ -10506,6 +10572,11 @@
 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 	 "get_qnodatapoll"},
 
+	{WE_CAP_TSF,
+	 0,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "cap_tsf"},
+
 	{WE_GET_TEMPERATURE,
 	 0,
 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
@@ -10565,6 +10636,15 @@
 	IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3,
 	0,
 	"setsapchannels"},
+	/* handlers for main ioctl */
+	{WLAN_PRIV_SET_NONE_GET_THREE_INT,
+	 0,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3,
+	 "" },
+	{WE_GET_TSF,
+	 0,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3,
+	 "get_tsf" },
 
 	{WE_SET_DUAL_MAC_SCAN_CONFIG,
 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3,
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 5c5ff30..0ffc244 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -5564,6 +5564,21 @@
 };
 
 /**
+ * struct stsf - the basic stsf structure
+ *
+ * @vdev_id: vdev id
+ * @tsf_low: low 32bits of tsf
+ * @tsf_high: high 32bits of tsf
+ *
+ * driver use this struct to store the tsf info
+ */
+struct stsf {
+	uint32_t vdev_id;
+	uint32_t tsf_low;
+	uint32_t tsf_high;
+};
+
+/**
  * struct egap_params - the enhanced green ap params
  * @vdev_id: vdev id
  * @enable: enable or disable the enhance green ap in firmware
diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h
index 23ab4d2..93aae03 100644
--- a/core/mac/inc/wni_api.h
+++ b/core/mac/inc/wni_api.h
@@ -248,6 +248,7 @@
 	eWNI_SME_HT40_OBSS_SCAN_IND, /* START and UPDATE OBSS SCAN Indication*/
 	eWNI_SME_SET_ANTENNA_MODE_REQ,
 	eWNI_SME_SET_ANTENNA_MODE_RESP,
+	eWNI_SME_TSF_EVENT,
 	eWNI_SME_MSG_TYPES_END
 };
 
diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h
index d836a36..73ce120 100644
--- a/core/sme/inc/sme_api.h
+++ b/core/sme/inc/sme_api.h
@@ -1096,6 +1096,8 @@
 
 void sme_update_fine_time_measurement_capab(tHalHandle hal, uint32_t val);
 QDF_STATUS sme_ht40_stop_obss_scan(tHalHandle hHal, uint32_t vdev_id);
+QDF_STATUS sme_set_tsfcb(tHalHandle hHal,
+	int (*cb_fn)(void *cb_ctx, struct stsf *ptsf), void *cb_ctx);
 
 QDF_STATUS sme_update_mimo_power_save(tHalHandle hHal,
 				      uint8_t is_ht_smps_enabled,
diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h
index 9e27ba2..f681208 100644
--- a/core/sme/inc/sme_internal.h
+++ b/core/sme/inc/sme_internal.h
@@ -197,6 +197,8 @@
 	bool enableSelfRecovery;
 	tCsrLinkStatusCallback linkStatusCallback;
 	void *linkStatusContext;
+	int (*get_tsf_cb)(void *pcb_cxt, struct stsf *ptsf);
+	void *get_tsf_cxt;
 	/* get temperature event context and callback */
 	void *pTemperatureCbContext;
 	void (*pGetTemperatureCb)(int temperature, void *context);
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index c12aef8..8785b0b 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -2805,6 +2805,14 @@
 			qdf_mem_free(pMsg->bodyptr);
 		}
 		break;
+	case eWNI_SME_TSF_EVENT:
+		if (pMac->sme.get_tsf_cb) {
+			pMac->sme.get_tsf_cb(pMac->sme.get_tsf_cxt,
+					(struct stsf *)pMsg->bodyptr);
+		}
+		if (pMsg->bodyptr)
+			qdf_mem_free(pMsg->bodyptr);
+		break;
 #ifdef WLAN_FEATURE_NAN
 	case eWNI_SME_NAN_EVENT:
 		if (pMsg->bodyptr) {
@@ -7300,6 +7308,29 @@
 
 #endif /* FEATURE_WLAN_SCAN_PNO */
 
+/*
+ * sme_set_tsfcb() - Set callback for TSF capture
+ * @hHal: Handler return by macOpen
+ * @cb_fn: Callback function pointer
+ * @db_ctx: Callback data
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_set_tsfcb(tHalHandle hHal,
+	int (*cb_fn)(void *cb_ctx, struct stsf *ptsf), void *cb_ctx)
+{
+	tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+	QDF_STATUS status;
+
+	status = sme_acquire_global_lock(&pMac->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		pMac->sme.get_tsf_cb = cb_fn;
+		pMac->sme.get_tsf_cxt = cb_ctx;
+		sme_release_global_lock(&pMac->sme);
+	}
+	return status;
+}
+
 QDF_STATUS sme_get_cfg_valid_channels(tHalHandle hHal, uint8_t *aValidChannels,
 				      uint32_t *len)
 {
diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h
index cec1e1e..4bf40d2 100644
--- a/core/wma/inc/wma_api.h
+++ b/core/wma/inc/wma_api.h
@@ -65,6 +65,8 @@
 	GEN_PARAM_DUMP_PCIE_ACCESS_LOG,
 #endif
 	GEN_PARAM_MODULATED_DTIM,
+	GEN_PARAM_CAPTURE_TSF,
+	GEN_PARAM_RESET_TSF_GPIO,
 } GEN_PARAM;
 
 #define VDEV_CMD 1
diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h
index 42c2c9d..4543eaa 100644
--- a/core/wma/inc/wma_internal.h
+++ b/core/wma/inc/wma_internal.h
@@ -1072,6 +1072,10 @@
 					   auto_sh_cmd);
 #endif
 
+int wma_vdev_tsf_handler(void *handle, uint8_t *data, uint32_t data_len);
+QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id);
+QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id);
+
 #ifdef WLAN_FEATURE_NAN
 
 QDF_STATUS wma_nan_req(void *wma_ptr, tpNanRequest nan_req);
diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c
index 447aa41..3e526e5 100644
--- a/core/wma/src/wma_features.c
+++ b/core/wma/src/wma_features.c
@@ -267,6 +267,177 @@
 	wma_post_link_status(pGetLinkStatus, LINK_STATUS_LEGACY);
 }
 
+#ifdef WLAN_FEATURE_TSF
+/**
+ * wma_vdev_tsf_handler() - handle tsf event indicated by FW
+ * @handle: wma context
+ * @data: event buffer
+ * @data len: length of event buffer
+ *
+ * Return: 0 on success
+ */
+int wma_vdev_tsf_handler(void *handle, uint8_t *data, uint32_t data_len)
+{
+	cds_msg_t tsf_msg = {0};
+	WMI_VDEV_TSF_REPORT_EVENTID_param_tlvs *param_buf;
+	wmi_vdev_tsf_report_event_fixed_param *tsf_event;
+	struct stsf *ptsf;
+
+	if (data == NULL) {
+		WMA_LOGE("%s: invalid pointer", __func__);
+		return -EINVAL;
+	}
+	ptsf = qdf_mem_malloc(sizeof(*ptsf));
+	if (NULL == ptsf) {
+		WMA_LOGE("%s: failed to allocate tsf data structure", __func__);
+		return -ENOMEM;
+	}
+
+	param_buf = (WMI_VDEV_TSF_REPORT_EVENTID_param_tlvs *)data;
+	tsf_event = param_buf->fixed_param;
+
+	ptsf->vdev_id = tsf_event->vdev_id;
+	ptsf->tsf_low = tsf_event->tsf_low;
+	ptsf->tsf_high = tsf_event->tsf_high;
+
+	WMA_LOGD("%s: receive WMI_VDEV_TSF_REPORT_EVENTID ", __func__);
+	WMA_LOGD("%s: vdev_id = %u,tsf_low =%u, tsf_high = %u", __func__,
+	ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high);
+
+	tsf_msg.type = eWNI_SME_TSF_EVENT;
+	tsf_msg.bodyptr = ptsf;
+	tsf_msg.bodyval = 0;
+
+	if (QDF_STATUS_SUCCESS !=
+		cds_mq_post_message(CDS_MQ_ID_SME, &tsf_msg)) {
+
+		WMA_LOGP("%s: Failed to post eWNI_SME_TSF_EVENT", __func__);
+		qdf_mem_free(ptsf);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * wma_capture_tsf() - send wmi to fw to capture tsf
+ * @wma_handle: wma handler
+ * @vdev_id: vdev id
+ *
+ * Return: wmi send state
+ */
+QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	wmi_buf_t buf;
+	wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd;
+	int ret;
+	int len = sizeof(*cmd);
+
+	buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
+	if (!buf) {
+		WMA_LOGP("%s: failed to allocate memory for cap tsf cmd",
+			 __func__);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	cmd = (wmi_vdev_tsf_tstamp_action_cmd_fixed_param *) wmi_buf_data(buf);
+	cmd->vdev_id = vdev_id;
+	cmd->tsf_action = TSF_TSTAMP_CAPTURE_REQ;
+
+	WMA_LOGD("%s :vdev_id %u, TSF_TSTAMP_CAPTURE_REQ", __func__,
+		 cmd->vdev_id);
+
+	WMITLV_SET_HDR(&cmd->tlv_header,
+	WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param,
+	WMITLV_GET_STRUCT_TLVLEN(
+	wmi_vdev_tsf_tstamp_action_cmd_fixed_param));
+
+	ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
+				   WMI_VDEV_TSF_TSTAMP_ACTION_CMDID);
+	if (ret != EOK) {
+		WMA_LOGE("wmi_unified_cmd_send returned Error %d", status);
+		status = QDF_STATUS_E_FAILURE;
+		goto error;
+	}
+
+	return QDF_STATUS_SUCCESS;
+
+error:
+	if (buf)
+		wmi_buf_free(buf);
+	return status;
+}
+
+/**
+ * wma_reset_tsf_gpio() - send wmi to fw to reset GPIO
+ * @wma_handle: wma handler
+ * @vdev_id: vdev id
+ *
+ * Return: wmi send state
+ */
+QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	wmi_buf_t buf;
+	wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd;
+	int ret;
+	int len = sizeof(*cmd);
+	uint8_t *buf_ptr;
+
+	buf = wmi_buf_alloc(wma_handle->wmi_handle, len);
+	if (!buf) {
+		WMA_LOGP("%s: failed to allocate memory for reset tsf gpio",
+			 __func__);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	buf_ptr = (uint8_t *) wmi_buf_data(buf);
+	cmd = (wmi_vdev_tsf_tstamp_action_cmd_fixed_param *) buf_ptr;
+	cmd->vdev_id = vdev_id;
+	cmd->tsf_action = TSF_TSTAMP_CAPTURE_RESET;
+
+	WMA_LOGD("%s :vdev_id %u, TSF_TSTAMP_CAPTURE_RESET", __func__,
+		 cmd->vdev_id);
+
+	WMITLV_SET_HDR(&cmd->tlv_header,
+		WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param,
+		WMITLV_GET_STRUCT_TLVLEN(
+				wmi_vdev_tsf_tstamp_action_cmd_fixed_param));
+
+	ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len,
+				   WMI_VDEV_TSF_TSTAMP_ACTION_CMDID);
+
+	if (ret != EOK) {
+		WMA_LOGE("wmi_unified_cmd_send returned Error %d", status);
+		status = QDF_STATUS_E_FAILURE;
+		goto error;
+	}
+	return QDF_STATUS_SUCCESS;
+
+error:
+	if (buf)
+		wmi_buf_free(buf);
+	return status;
+}
+#else
+QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+int wma_vdev_tsf_handler(void *handle, uint8_t *data, uint32_t data_len)
+{
+	return 0;
+}
+#endif
+
+
+
 #ifdef FEATURE_WLAN_LPHB
 /**
  * wma_lphb_conf_hbenable() - enable command of LPHB configuration requests
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index 723ff49..b484244 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -919,6 +919,12 @@
 						privcmd->param_value,
 						privcmd->param_sec_value);
 			break;
+		case GEN_PARAM_CAPTURE_TSF:
+			ret = wma_capture_tsf(wma, privcmd->param_value);
+			break;
+		case GEN_PARAM_RESET_TSF_GPIO:
+			ret = wma_reset_tsf_gpio(wma, privcmd->param_value);
+			break;
 #ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
 		case GEN_PARAM_DUMP_PCIE_ACCESS_LOG:
 			htc_dump(wma->htc_handle, PCIE_DUMP, false);
@@ -2755,6 +2761,16 @@
 		goto end;
 	}
 
+	status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
+						WMI_VDEV_TSF_REPORT_EVENTID,
+						wma_vdev_tsf_handler,
+						WMA_RX_SERIALIZER_CTX);
+	if (0 != status) {
+		WMA_LOGP("%s: Failed to register tsf callback", __func__);
+		qdf_status = QDF_STATUS_E_FAILURE;
+		goto end;
+	}
+
 	/* Initialize the log flush complete event handler */
 	status = wmi_unified_register_event_handler(wma_handle->wmi_handle,
 			WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID,