qcacld-3.0: Add vendor command for TSF operations

Update TSF feature for vendor command QCA_NL80211_VENDOR_SUBCMD_TSF
to support TSF operations.

Change-Id: I89abf14b9b7d8ee8fe1c12f7684c87e4dee9bfb0
CRs-fixed: 997799
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index cdd7789..22757b1 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -960,6 +960,7 @@
 	uint32_t tsf_high;
 	/* TSF capture state */
 	enum hdd_tsf_capture_state tsf_state;
+	uint64_t tsf_sync_soc_timer;
 #endif
 
 	hdd_cfg80211_state_t cfg80211State;
diff --git a/core/hdd/inc/wlan_hdd_tsf.h b/core/hdd/inc/wlan_hdd_tsf.h
index f251327..6d7ba78 100644
--- a/core/hdd/inc/wlan_hdd_tsf.h
+++ b/core/hdd/inc/wlan_hdd_tsf.h
@@ -64,6 +64,10 @@
 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);
+int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
+					struct wireless_dev *wdev,
+					const void *data,
+					int data_len);
 #else
 static inline void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx)
 {
@@ -81,6 +85,14 @@
 {
 	return -ENOTSUPP;
 }
+
+static inline int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
+					struct wireless_dev *wdev,
+					const void *data,
+					int data_len)
+{
+	return -ENOTSUPP;
+}
 #endif
 
 #endif
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index dad64ab..b4a2192 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -83,6 +83,7 @@
 #include "wlan_hdd_memdump.h"
 
 #include "wlan_hdd_ocb.h"
+#include "wlan_hdd_tsf.h"
 
 #include "wlan_hdd_subnet_detect.h"
 
@@ -1052,6 +1053,12 @@
 		.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP
 	},
 #endif /* WLAN_FEATURE_MEMDUMP */
+#ifdef WLAN_FEATURE_TSF
+	[QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX] = {
+		.vendor_id = QCA_NL80211_VENDOR_ID,
+		.subcmd = QCA_NL80211_VENDOR_SUBCMD_TSF
+	},
+#endif
 	[QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX] = {
 		.vendor_id = QCA_NL80211_VENDOR_ID,
 		.subcmd = QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE
@@ -5550,6 +5557,16 @@
 			WIPHY_VENDOR_CMD_NEED_RUNNING,
 		.doit = wlan_hdd_cfg80211_set_probable_oper_channel
 	},
+#ifdef WLAN_FEATURE_TSF
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TSF,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+			WIPHY_VENDOR_CMD_NEED_NETDEV |
+			WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = wlan_hdd_cfg80211_handle_tsf_cmd
+	},
+#endif
 #ifdef FEATURE_WLAN_TDLS
 	{
 		.info.vendor_id = QCA_NL80211_VENDOR_ID,
diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h
index b2e6aa2..0144b82 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.h
+++ b/core/hdd/src/wlan_hdd_cfg80211.h
@@ -258,6 +258,7 @@
  * @QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG: set gateway parameters
  * @QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE: set tx power by percentage
  * @QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB: reduce tx power by DB
+ * @QCA_NL80211_VENDOR_SUBCMD_TSF: TSF operations command
  */
 
 enum qca_nl80211_vendor_subcmds {
@@ -377,6 +378,7 @@
 	QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109,
 	/* Tx power scaling in db subcommands */
 	QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB = 115,
+	QCA_NL80211_VENDOR_SUBCMD_TSF = 119,
 
 };
 
@@ -438,6 +440,7 @@
  *	vendor scan complete event  index
  * @QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG_INDEX:
  *	update gateway parameters index
+ * @QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX: TSF response events index
  */
 
 enum qca_nl80211_vendor_subcmds_index {
@@ -507,6 +510,9 @@
 	QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX,
 	QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX,
 	QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG_INDEX,
+#ifdef WLAN_FEATURE_TSF
+	QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX,
+#endif
 };
 
 /**
@@ -2176,6 +2182,38 @@
 };
 
 /**
+ * enum qca_vendor_attr_get_tsf: Vendor attributes for TSF capture
+ * @QCA_WLAN_VENDOR_ATTR_TSF_INVALID: Invalid attribute value
+ * @QCA_WLAN_VENDOR_ATTR_TSF_CMD: enum qca_tsf_operation (u32)
+ * @QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE: Unsigned 64 bit TSF timer value
+ * @QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE: Unsigned 64 bit Synchronized
+ *	SOC timer value at TSF capture
+ * @QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST: after last
+ * @QCA_WLAN_VENDOR_ATTR_TSF_MAX: Max value
+ */
+enum qca_vendor_attr_tsf_cmd {
+	QCA_WLAN_VENDOR_ATTR_TSF_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_TSF_CMD,
+	QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE,
+	QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE,
+	QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_TSF_MAX =
+		QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_tsf_operation: TSF driver commands
+ * @QCA_TSF_CAPTURE: Initiate TSF Capture
+ * @QCA_TSF_GET: Get TSF capture value
+ * @QCA_TSF_SYNC_GET: Initiate TSF capture and return with captured value
+ */
+enum qca_tsf_cmd {
+	QCA_TSF_CAPTURE,
+	QCA_TSF_GET,
+	QCA_TSF_SYNC_GET,
+};
+
+/**
  * enum qca_vendor_attr_get_preferred_freq_list - get preferred channel list
  * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_INVALID: invalid value
  * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE: interface type
diff --git a/core/hdd/src/wlan_hdd_tsf.c b/core/hdd/src/wlan_hdd_tsf.c
index 2563a94..e98759a 100644
--- a/core/hdd/src/wlan_hdd_tsf.c
+++ b/core/hdd/src/wlan_hdd_tsf.c
@@ -32,6 +32,8 @@
 #include "wlan_hdd_main.h"
 #include "wma_api.h"
 
+static struct completion tsf_sync_get_completion_evt;
+#define WLAN_TSF_SYNC_GET_TIMEOUT 2000
 /**
  * hdd_capture_tsf() - capture tsf
  * @adapter: pointer to adapter
@@ -48,7 +50,7 @@
 	hdd_station_ctx_t *hdd_sta_ctx;
 
 	if (adapter == NULL || buf == NULL) {
-		hdd_err(FL("invalid pointer"));
+		hdd_err("invalid pointer");
 		return -EINVAL;
 	}
 	if (len != 1)
@@ -57,14 +59,14 @@
 	/* Reset TSF value for new capture */
 	adapter->tsf_high = 0;
 	adapter->tsf_low = 0;
+	adapter->tsf_sync_soc_timer = 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"));
+				eConnectionState_Associated) {
+			hdd_err("failed to cap tsf, not connect with ap");
 			buf[0] = TSF_STA_NOT_CONNECTED_NO_TSF;
 			return ret;
 		}
@@ -72,24 +74,25 @@
 	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"));
+		hdd_err("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;
+		hdd_err("current in capture state, pls reset");
+		buf[0] = TSF_CURRENT_IN_CAP_STATE;
 	} else {
-		hdd_info(FL("Send TSF capture to FW"));
+		hdd_info("Send TSF capture to FW");
 		buf[0] = TSF_RETURN;
 		adapter->tsf_state = TSF_CAP_STATE;
+		init_completion(&tsf_sync_get_completion_evt);
 		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"));
+			hdd_err("capture fail");
 			buf[0] = TSF_CAPTURE_FAIL;
 			adapter->tsf_state = TSF_IDLE;
 		}
@@ -98,6 +101,39 @@
 }
 
 /**
+ * hdd_tsf_reset_gpio() - Reset TSF GPIO used for host timer sync
+ * @adapter: pointer to adapter
+ *
+ * This function send WMI command to reset GPIO configured in FW after
+ * TSF get operation.
+ *
+ * Return: TSF_RETURN on Success, TSF_RESET_GPIO_FAIL on failure
+ */
+#ifdef QCA_WIFI_3_0
+int hdd_tsf_reset_gpio(struct hdd_adapter_s *adapter)
+{
+	/* No GPIO Host timer sync for integrated WIFI Device */
+	return TSF_RETURN;
+}
+#else
+int hdd_tsf_reset_gpio(struct hdd_adapter_s *adapter)
+{
+	int ret;
+	ret = wma_cli_set_command((int)adapter->sessionId,
+			(int)GEN_PARAM_RESET_TSF_GPIO, adapter->sessionId,
+			GEN_CMD);
+
+	if (ret != 0) {
+		hdd_err("tsf reset GPIO fail ");
+		ret = TSF_RESET_GPIO_FAIL;
+	} else {
+		ret = TSF_RETURN;
+	}
+	return ret;
+}
+#endif
+
+/**
  * hdd_indicate_tsf() - return tsf to uplayer
  * @adapter: pointer to adapter
  * @buf: pointer to uplayer buf
@@ -109,11 +145,10 @@
  */
 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"));
+		hdd_err("invalid pointer");
 		return -EINVAL;
 	}
 
@@ -126,42 +161,32 @@
 		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"));
+				eConnectionState_Associated) {
+			hdd_info("fail to get tsf, sta in disconnected");
 			buf[0] = TSF_STA_NOT_CONNECTED_NO_TSF;
-			return ret;
+			return 0;
 		}
 	}
 	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"));
+			adapter->device_mode == QDF_P2P_GO_MODE) &&
+			!(test_bit(SOFTAP_BSS_STARTED,
+			&adapter->event_flags))) {
+		hdd_err("Soft AP / P2p GO not beaconing");
 		buf[0] = TSF_SAP_NOT_STARTED_NO_TSF;
-		return ret;
+		return 0;
 	}
 	if (adapter->tsf_high == 0 && adapter->tsf_low == 0) {
-		hdd_info(FL("TSF value not received"));
+		hdd_info("TSF value not received");
 		buf[0] = TSF_NOT_RETURNED_BY_FW;
 	} else {
-		buf[0] = TSF_RETURN;
+		buf[0] = hdd_tsf_reset_gpio(adapter);
 		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"),
+		hdd_info("get tsf cmd,status=%u, tsf_low=%u, tsf_high=%u",
 			buf[0], buf[1], buf[2]);
 	}
-	return ret;
+	return 0;
 }
 
 /**
@@ -183,36 +208,184 @@
 	int status;
 
 	if (pcb_cxt == NULL || ptsf == NULL) {
-		hdd_err(FL("HDD context is not valid"));
+		hdd_err("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"));
+		hdd_err("failed to find adapter");
 		return -EINVAL;
 	}
-
-	hdd_info(FL("tsf cb handle event, device_mode is %d"),
+	hdd_info("tsf cb handle event, device_mode is %d",
 		adapter->device_mode);
 
 	adapter->tsf_low = ptsf->tsf_low;
 	adapter->tsf_high = ptsf->tsf_high;
+	adapter->tsf_sync_soc_timer = ((uint64_t) ptsf->soc_timer_high << 32 |
+						  ptsf->soc_timer_low);
 
-	hdd_info(FL("hdd_get_tsf_cb sta=%u, tsf_low=%u, tsf_high=%u"),
-		ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high);
+	complete(&tsf_sync_get_completion_evt);
+	hdd_info("Vdev=%u, tsf_low=%u, tsf_high=%u soc_timer=%llu",
+		ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high,
+		adapter->tsf_sync_soc_timer);
 	return 0;
 }
 
 /**
+ * __wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations
+ * @wiphy: Pointer to wireless phy
+ * @wdev: Pointer to wireless device
+ * @data: Pointer to data
+ * @data_len: Data length
+ *
+ * Handle TSF SET / GET operation from userspace
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
+					struct wireless_dev *wdev,
+					const void *data,
+					int data_len)
+{
+	struct net_device *dev = wdev->netdev;
+	hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1];
+	int status, ret;
+	struct sk_buff *reply_skb;
+	uint32_t tsf_op_resp[3], tsf_cmd;
+
+	ENTER_DEV(wdev->netdev);
+
+	status = wlan_hdd_validate_context(hdd_ctx);
+	if (0 != status)
+		return -EINVAL;
+
+	if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TSF_MAX, data,
+		      data_len, NULL)) {
+		hdd_err("Invalid TSF cmd");
+		return -EINVAL;
+	}
+
+	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]) {
+		hdd_err("Invalid TSF cmd");
+		return -EINVAL;
+	}
+	tsf_cmd = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]);
+
+	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]) {
+		case TSF_RETURN:
+			status = 0;
+			break;
+		case TSF_CURRENT_IN_CAP_STATE:
+			status = -EALREADY;
+			break;
+		case TSF_STA_NOT_CONNECTED_NO_TSF:
+		case TSF_SAP_NOT_STARTED_NO_TSF:
+			status = -EPERM;
+			break;
+		default:
+		case TSF_CAPTURE_FAIL:
+			status = -EINVAL;
+			break;
+		}
+	}
+	if (status < 0)
+		goto end;
+
+	if (tsf_cmd == QCA_TSF_SYNC_GET) {
+		ret = wait_for_completion_timeout(&tsf_sync_get_completion_evt,
+			msecs_to_jiffies(WLAN_TSF_SYNC_GET_TIMEOUT));
+		if (ret == 0) {
+			status = -ETIMEDOUT;
+			goto end;
+		}
+	}
+
+	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;
+		}
+		if (status != 0)
+			goto end;
+
+		reply_skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
+					sizeof(uint64_t) * 2 + NLMSG_HDRLEN,
+					QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX,
+					GFP_KERNEL);
+		if (!reply_skb) {
+			hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
+			status = -ENOMEM;
+			goto end;
+		}
+		if (nla_put_u64(reply_skb, QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE,
+				((uint64_t) adapter->tsf_high << 32 |
+				adapter->tsf_low)) ||
+				nla_put_u64(reply_skb,
+				QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE,
+				adapter->tsf_sync_soc_timer)){
+			hdd_err("nla put fail");
+			kfree_skb(reply_skb);
+			status = -EINVAL;
+			goto end;
+		}
+		status = cfg80211_vendor_cmd_reply(reply_skb);
+	}
+
+end:
+	hdd_info("TSF operation %d Status: %d", tsf_cmd, status);
+	return status;
+}
+
+/**
+ * wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations
+ * @wiphy: Pointer to wireless phy
+ * @wdev: Pointer to wireless device
+ * @data: Pointer to data
+ * @data_len: Data length
+ *
+ * Handle TSF SET / GET operation from userspace
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
+					struct wireless_dev *wdev,
+					const void *data,
+					int data_len)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __wlan_hdd_cfg80211_handle_tsf_cmd(wiphy, wdev, data, data_len);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
+
+/**
  * wlan_hdd_tsf_init() - set callback to handle tsf value.
  * @hdd_ctx: pointer to the struct hdd_context_s
  *
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 7cb2188..8cfe067 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -5589,6 +5589,8 @@
  * @vdev_id: vdev id
  * @tsf_low: low 32bits of tsf
  * @tsf_high: high 32bits of tsf
+ * @soc_timer_low: low 32bits of synced SOC timer value
+ * @soc_timer_high: high 32bits of synced SOC timer value
  *
  * driver use this struct to store the tsf info
  */
@@ -5596,6 +5598,8 @@
 	uint32_t vdev_id;
 	uint32_t tsf_low;
 	uint32_t tsf_high;
+	uint32_t soc_timer_low;
+	uint32_t soc_timer_high;
 };
 
 /**
diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c
index 00c2df0..b59374b 100644
--- a/core/wma/src/wma_features.c
+++ b/core/wma/src/wma_features.c
@@ -299,6 +299,8 @@
 	ptsf->vdev_id = tsf_event->vdev_id;
 	ptsf->tsf_low = tsf_event->tsf_low;
 	ptsf->tsf_high = tsf_event->tsf_high;
+	ptsf->soc_timer_low = tsf_event->qtimer_low;
+	ptsf->soc_timer_high = tsf_event->qtimer_high;
 
 	WMA_LOGD("%s: receive WMI_VDEV_TSF_REPORT_EVENTID ", __func__);
 	WMA_LOGD("%s: vdev_id = %u,tsf_low =%u, tsf_high = %u", __func__,
@@ -318,6 +320,11 @@
 	return 0;
 }
 
+#ifdef QCA_WIFI_3_0
+#define TSF_FW_ACTION_CMD TSF_TSTAMP_QTIMER_CAPTURE_REQ
+#else
+#define TSF_FW_ACTION_CMD TSF_TSTAMP_CAPTURE_REQ
+#endif
 /**
  * wma_capture_tsf() - send wmi to fw to capture tsf
  * @wma_handle: wma handler
@@ -342,10 +349,9 @@
 
 	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);
+	cmd->tsf_action = TSF_FW_ACTION_CMD;
+	WMA_LOGD("%s :vdev_id %u, tsf_cmd: %d", __func__, cmd->vdev_id,
+						cmd->tsf_action);
 
 	WMITLV_SET_HDR(&cmd->tlv_header,
 	WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param,