xref: /wlan-dirver/qcacld-3.0/core/hdd/src/wlan_hdd_tsf.c (revision d1eb296939c4184ce7e8a921bf6ffe874f574400)
1 /*
2  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * wlan_hdd_tsf.c - WLAN Host Device Driver tsf related implementation
22  */
23 
24 #include "osif_sync.h"
25 #include "wlan_hdd_main.h"
26 #include "wlan_hdd_tsf.h"
27 #include "wma_api.h"
28 #include "wlan_fwol_ucfg_api.h"
29 #include <qca_vendor.h>
30 #include <linux/errqueue.h>
31 #if defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ) || \
32 	defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
33 #include <linux/gpio.h>
34 #endif
35 
36 #include "ol_txrx_api.h"
37 #ifdef WLAN_FEATURE_TSF_UPLINK_DELAY
38 #include <cdp_txrx_ctrl.h>
39 #endif
40 
41 #ifdef WLAN_FEATURE_TSF_PLUS
42 #if !defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && \
43 	!defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) && \
44 	!defined(WLAN_FEATURE_TSF_TIMER_SYNC)
45 static int tsf_gpio_irq_num = -1;
46 #endif
47 #endif
48 static qdf_event_t tsf_sync_get_completion_evt;
49 #define WLAN_TSF_SYNC_GET_TIMEOUT 2000
50 #define WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS 500
51 #define WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS 100
52 #ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC
53 #define WLAN_HDD_SOFTAP_INTERVAL_TIMES 1
54 #else
55 #define WLAN_HDD_SOFTAP_INTERVAL_TIMES 100
56 #endif
57 #define OUTPUT_HIGH 1
58 #define OUTPUT_LOW 0
59 
60 #ifdef WLAN_FEATURE_TSF_PLUS
61 #if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) || \
62 	defined(WLAN_FEATURE_TSF_TIMER_SYNC)
63 static void hdd_update_timestamp(struct hdd_adapter *adapter);
64 #else
65 static void
66 hdd_update_timestamp(struct hdd_adapter *adapter,
67 		     uint64_t target_time, uint64_t host_time);
68 #endif
69 #endif
70 
71 #ifdef QCA_GET_TSF_VIA_REG
72 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf);
73 
74 /**
75  * struct hdd_tsf_report - TSF report filled in by DP layer
76  * @vdev_id: vdev id for which TSF values is to be read
77  * @tsf_id: tsf if used to read TSF report
78  * @mac_id: lmac_id for which TSF values are read
79  * @tsf: 64 bit tsf value as read from scratch registers
80  * @tsf_sync_soc_time: host qtimer time when scratch registers are read
81  *
82  * The structure is used by the upper layers to pass vdev_id, tsf_id and mac_id
83  * information to DP layer and get tsf time and host time when TSF was read.
84  */
85 struct hdd_tsf_report {
86 	uint32_t vdev_id;
87 	uint32_t tsf_id;
88 	uint32_t mac_id;
89 	uint64_t tsf;
90 	uint64_t tsf_sync_soc_time;
91 };
92 #endif
93 
94 /**
95  * enum hdd_tsf_op_result - result of tsf operation
96  *
97  * HDD_TSF_OP_SUCC:  succeed
98  * HDD_TSF_OP_FAIL:  fail
99  */
100 enum hdd_tsf_op_result {
101 	HDD_TSF_OP_SUCC,
102 	HDD_TSF_OP_FAIL
103 };
104 
105 #ifdef WLAN_FEATURE_TSF_PLUS
106 #ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC
107 #define WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL 1
108 #else
109 #define WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL 9
110 #endif
111 static inline void hdd_set_th_sync_status(struct hdd_adapter *adapter,
112 					  bool initialized)
113 {
114 	qdf_atomic_set(&adapter->tsf_sync_ready_flag,
115 		       (initialized ? 1 : 0));
116 }
117 
118 static inline bool hdd_get_th_sync_status(struct hdd_adapter *adapter)
119 {
120 	return qdf_atomic_read(&adapter->tsf_sync_ready_flag) != 0;
121 }
122 
123 #else
124 static inline bool hdd_get_th_sync_status(struct hdd_adapter *adapter)
125 {
126 	return true;
127 }
128 #endif
129 
130 static
131 enum hdd_tsf_get_state hdd_tsf_check_conn_state(struct hdd_adapter *adapter)
132 {
133 	enum hdd_tsf_get_state ret = TSF_RETURN;
134 
135 	if (adapter->device_mode == QDF_STA_MODE ||
136 			adapter->device_mode == QDF_P2P_CLIENT_MODE) {
137 		if (!hdd_cm_is_vdev_associated(adapter)) {
138 			hdd_err("failed to cap tsf, not connect with ap");
139 			ret = TSF_STA_NOT_CONNECTED_NO_TSF;
140 		}
141 	} else if ((adapter->device_mode == QDF_SAP_MODE ||
142 				adapter->device_mode == QDF_P2P_GO_MODE) &&
143 			!(test_bit(SOFTAP_BSS_STARTED,
144 					&adapter->event_flags))) {
145 		hdd_err("Soft AP / P2p GO not beaconing");
146 		ret = TSF_SAP_NOT_STARTED_NO_TSF;
147 	}
148 	return ret;
149 }
150 
151 static bool hdd_tsf_is_initialized(struct hdd_adapter *adapter)
152 {
153 	struct hdd_context *hddctx;
154 
155 	if (!adapter) {
156 		hdd_err("invalid adapter");
157 		return false;
158 	}
159 
160 	hddctx = WLAN_HDD_GET_CTX(adapter);
161 	if (!hddctx) {
162 		hdd_err("invalid hdd context");
163 		return false;
164 	}
165 
166 	if (!qdf_atomic_read(&hddctx->tsf_ready_flag) ||
167 	    !hdd_get_th_sync_status(adapter)) {
168 		hdd_err("TSF is not initialized");
169 		return false;
170 	}
171 
172 	return true;
173 }
174 
175 #if (defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && \
176 	defined(WLAN_FEATURE_TSF_PLUS)) || \
177 	defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) || \
178 	defined(WLAN_FEATURE_TSF_TIMER_SYNC)
179 /**
180  * hdd_tsf_reset_gpio() - Reset TSF GPIO used for host timer sync
181  * @adapter: pointer to adapter
182  *
183  * This function send WMI command to reset GPIO configured in FW after
184  * TSF get operation.
185  *
186  * Return: TSF_RETURN on Success, TSF_RESET_GPIO_FAIL on failure
187  */
188 static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter)
189 {
190 	/* No GPIO Host timer sync for integrated WIFI Device */
191 	return TSF_RETURN;
192 }
193 
194 /**
195  * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync
196  * @hdd_ctx: pointer to hdd context
197  *
198  * This function is a dummy function for adrastea arch
199  *
200  * Return: QDF_STATUS_SUCCESS on Success
201  */
202 
203 static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx)
204 {
205 	return QDF_STATUS_SUCCESS;
206 }
207 #else
208 static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter)
209 {
210 	int ret;
211 
212 	ret = wma_cli_set_command((int)adapter->vdev_id,
213 				  (int)GEN_PARAM_RESET_TSF_GPIO,
214 				  adapter->vdev_id,
215 				  GEN_CMD);
216 
217 	if (ret != 0) {
218 		hdd_err("tsf reset GPIO fail ");
219 		ret = TSF_RESET_GPIO_FAIL;
220 	} else {
221 		ret = TSF_RETURN;
222 	}
223 	return ret;
224 }
225 
226 /**
227  * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync
228  * @hdd_ctx: pointer to hdd context
229  *
230  * This function check GPIO and set GPIO as IRQ to FW side on
231  * none Adrastea arch
232  *
233  * Return: QDF_STATUS_SUCCESS on Success, others on Failure.
234  */
235 static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx)
236 {
237 	QDF_STATUS status;
238 	uint32_t tsf_gpio_pin = TSF_GPIO_PIN_INVALID;
239 
240 	status = ucfg_fwol_get_tsf_gpio_pin(hdd_ctx->psoc, &tsf_gpio_pin);
241 	if (QDF_IS_STATUS_ERROR(status))
242 		return QDF_STATUS_E_INVAL;
243 
244 	if (tsf_gpio_pin == TSF_GPIO_PIN_INVALID)
245 		return QDF_STATUS_E_INVAL;
246 
247 	status = sme_set_tsf_gpio(hdd_ctx->mac_handle,
248 				  tsf_gpio_pin);
249 
250 	return status;
251 }
252 #endif
253 
254 #ifdef WLAN_FEATURE_TSF_PLUS
255 static bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd)
256 {
257 	uint32_t tsf_ptp_options;
258 
259 	if (hdd && QDF_IS_STATUS_SUCCESS(
260 	    ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
261 		return !!tsf_ptp_options;
262 	else
263 		return false;
264 }
265 
266 bool hdd_tsf_is_tx_set(struct hdd_context *hdd)
267 {
268 	uint32_t tsf_ptp_options;
269 
270 	if (hdd && QDF_IS_STATUS_SUCCESS(
271 	    ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
272 		return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_TX;
273 	else
274 		return false;
275 }
276 
277 bool hdd_tsf_is_rx_set(struct hdd_context *hdd)
278 {
279 	uint32_t tsf_ptp_options;
280 
281 	if (hdd && QDF_IS_STATUS_SUCCESS(
282 	    ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
283 		return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_RX;
284 	else
285 		return false;
286 }
287 
288 bool hdd_tsf_is_raw_set(struct hdd_context *hdd)
289 {
290 	uint32_t tsf_ptp_options;
291 
292 	if (hdd && QDF_IS_STATUS_SUCCESS(
293 	    ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
294 		return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_RAW;
295 	else
296 		return false;
297 }
298 
299 bool hdd_tsf_is_dbg_fs_set(struct hdd_context *hdd)
300 {
301 	uint32_t tsf_ptp_options;
302 
303 	if (hdd && QDF_IS_STATUS_SUCCESS(
304 	    ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
305 		return tsf_ptp_options & CFG_SET_TSF_DBG_FS;
306 	else
307 		return false;
308 }
309 
310 bool hdd_tsf_is_tsf64_tx_set(struct hdd_context *hdd)
311 {
312 	uint32_t tsf_ptp_options;
313 
314 	if (hdd && QDF_IS_STATUS_SUCCESS(
315 	    ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
316 		return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_TSF64_TX;
317 	else
318 		return false;
319 }
320 
321 static bool hdd_is_tsf_sync_enabled(struct hdd_context *hdd)
322 {
323 	bool is_tsf_sync_enable;
324 
325 	if (hdd && QDF_IS_STATUS_SUCCESS(
326 	    ucfg_fwol_get_tsf_sync_enable(hdd->psoc, &is_tsf_sync_enable)))
327 		return is_tsf_sync_enable;
328 	else
329 		return false;
330 }
331 
332 void hdd_update_dynamic_tsf_sync(struct hdd_adapter *adapter)
333 {
334 	adapter->enable_dynamic_tsf_sync =
335 			hdd_is_tsf_sync_enabled(adapter->hdd_ctx);
336 }
337 #else
338 
339 static bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd)
340 {
341 	return false;
342 }
343 #endif
344 
345 #ifdef WLAN_FEATURE_TSF_PLUS
346 static inline
347 uint64_t hdd_get_monotonic_host_time(struct hdd_context *hdd_ctx)
348 {
349 	return hdd_tsf_is_raw_set(hdd_ctx) ?
350 		ktime_get_ns() : ktime_get_real_ns();
351 }
352 #endif
353 
354 #if defined(WLAN_FEATURE_TSF_PLUS) && \
355 	defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
356 #define MAX_CONTINUOUS_RETRY_CNT 10
357 static uint32_t
358 hdd_wlan_retry_tsf_cap(struct hdd_adapter *adapter)
359 {
360 	struct hdd_context *hddctx;
361 	int count = adapter->continuous_cap_retry_count;
362 
363 	hddctx = WLAN_HDD_GET_CTX(adapter);
364 	if (count == MAX_CONTINUOUS_RETRY_CNT) {
365 		hdd_debug("Max retry count reached");
366 		return 0;
367 	}
368 	qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
369 	count++;
370 	adapter->continuous_cap_retry_count = count;
371 	return (count * WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS);
372 }
373 
374 static void
375 hdd_wlan_restart_tsf_cap(struct hdd_adapter *adapter)
376 {
377 	struct hdd_context *hddctx;
378 	int count = adapter->continuous_cap_retry_count;
379 
380 	hddctx = WLAN_HDD_GET_CTX(adapter);
381 	if (count == MAX_CONTINUOUS_RETRY_CNT) {
382 		hdd_debug("Restart TSF CAP");
383 		qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
384 		adapter->continuous_cap_retry_count = 0;
385 		qdf_mc_timer_start(&adapter->host_target_sync_timer,
386 				   WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS);
387 	}
388 }
389 
390 static void
391 hdd_update_host_time(struct hdd_adapter *adapter)
392 {
393 	struct hdd_context *hdd_ctx;
394 	u64 host_time;
395 	char *name = NULL;
396 
397 	hdd_ctx = adapter->hdd_ctx;
398 
399 	if (!hdd_tsf_is_initialized(adapter)) {
400 		hdd_err("tsf is not init, exit");
401 		return;
402 	}
403 
404 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
405 	hdd_update_timestamp(adapter, 0, host_time);
406 	name = adapter->dev->name;
407 
408 	hdd_debug("iface: %s - host_time: %llu",
409 		  (!name ? "none" : name), host_time);
410 }
411 
412 static
413 void hdd_tsf_ext_gpio_sync_work(void *data)
414 {
415 	QDF_STATUS status;
416 	struct hdd_adapter *adapter;
417 	struct hdd_context *hdd_ctx;
418 	uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID;
419 
420 	adapter = data;
421 	hdd_ctx = adapter->hdd_ctx;
422 	status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc,
423 						      &tsf_sync_gpio_pin);
424 	if (QDF_IS_STATUS_ERROR(status)) {
425 		hdd_err("tsf sync gpio host pin error");
426 		return;
427 	}
428 	gpio_set_value(tsf_sync_gpio_pin, OUTPUT_HIGH);
429 	hdd_update_host_time(adapter);
430 	usleep_range(50, 100);
431 	gpio_set_value(tsf_sync_gpio_pin, OUTPUT_LOW);
432 
433 	status = wma_cli_set_command((int)adapter->vdev_id,
434 				     (int)GEN_PARAM_CAPTURE_TSF,
435 				     adapter->vdev_id, GEN_CMD);
436 	if (status != QDF_STATUS_SUCCESS) {
437 		hdd_err("cap tsf fail");
438 		qdf_mc_timer_stop(&adapter->host_capture_req_timer);
439 		qdf_mc_timer_destroy(&adapter->host_capture_req_timer);
440 	}
441 }
442 
443 static void
444 hdd_tsf_gpio_sync_work_init(struct hdd_adapter *adapter)
445 {
446 	qdf_create_work(0, &adapter->gpio_tsf_sync_work,
447 			hdd_tsf_ext_gpio_sync_work, adapter);
448 }
449 
450 static void
451 hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter *adapter)
452 {
453 	qdf_destroy_work(0, &adapter->gpio_tsf_sync_work);
454 }
455 
456 static void
457 hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter *adapter)
458 {
459 	qdf_cancel_work(&adapter->gpio_tsf_sync_work);
460 }
461 
462 static void
463 hdd_tsf_start_ext_gpio_sync(struct hdd_adapter *adapter)
464 {
465 	qdf_sched_work(0, &adapter->gpio_tsf_sync_work);
466 }
467 
468 static bool hdd_tsf_cap_sync_send(struct hdd_adapter *adapter)
469 {
470 	hdd_tsf_start_ext_gpio_sync(adapter);
471 	return true;
472 }
473 #elif defined(WLAN_FEATURE_TSF_PLUS) && \
474 	!defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
475 static void
476 hdd_wlan_restart_tsf_cap(struct hdd_adapter *adapter)
477 {
478 }
479 
480 static void
481 hdd_tsf_gpio_sync_work_init(struct hdd_adapter *adapter)
482 {
483 }
484 
485 static void
486 hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter *adapter)
487 {
488 }
489 
490 static void
491 hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter *adapter)
492 {
493 }
494 
495 static void
496 hdd_tsf_start_ext_gpio_sync(struct hdd_adapter *adapter)
497 {
498 }
499 
500 static bool
501 hdd_tsf_cap_sync_send(struct hdd_adapter *adapter)
502 {
503 	hdd_tsf_start_ext_gpio_sync(adapter);
504 	return false;
505 }
506 
507 #else
508 static bool hdd_tsf_cap_sync_send(struct hdd_adapter *adapter)
509 {
510 	return false;
511 }
512 #endif
513 
514 #ifdef WLAN_FEATURE_TSF_TIMER_SYNC
515 /**
516  * hdd_convert_qtime_to_us() - convert qtime to us
517  * @time: QTIMER ticks for adrastea and us for Lithium
518  *
519  * This function converts qtime to us.
520  *
521  * Return: Time in microseconds
522  */
523 static inline uint64_t
524 hdd_convert_qtime_to_us(uint64_t time)
525 {
526 	return time;
527 }
528 
529 #else
530 static inline uint64_t
531 hdd_convert_qtime_to_us(uint64_t time)
532 {
533 	return qdf_log_timestamp_to_usecs(time);
534 }
535 #endif
536 
537 /**
538  * hdd_capture_tsf_internal_via_wmi() - convert qtime to us
539  * @adapter: pointer to adapter
540  * @buf: in case of failure update with fail
541  * @len: buffer length
542  *
543  * Return: result of tsf operation
544  */
545 static enum hdd_tsf_op_result
546 hdd_capture_tsf_internal_via_wmi(struct hdd_adapter *adapter, uint32_t *buf,
547 				 int len)
548 {
549 	int ret;
550 	struct hdd_context *hddctx = adapter->hdd_ctx;
551 
552 	ret = wma_cli_set_command((int)adapter->vdev_id,
553 				  (int)GEN_PARAM_CAPTURE_TSF,
554 				  adapter->vdev_id, GEN_CMD);
555 	if (ret != QDF_STATUS_SUCCESS) {
556 		hdd_err("cap tsf fail");
557 		buf[0] = TSF_CAPTURE_FAIL;
558 		hddctx->cap_tsf_context = NULL;
559 		qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
560 		qdf_mc_timer_stop(&adapter->host_capture_req_timer);
561 		qdf_mc_timer_destroy(&adapter->host_capture_req_timer);
562 	}
563 	return HDD_TSF_OP_SUCC;
564 }
565 
566 #ifndef QCA_GET_TSF_VIA_REG
567 static inline
568 enum hdd_tsf_op_result _hdd_capture_tsf_internal(struct hdd_adapter *adapter,
569 						 uint32_t *buf, int len)
570 {
571 	return hdd_capture_tsf_internal_via_wmi(adapter, buf, len);
572 }
573 
574 static inline void wlan_hdd_tsf_reg_update_details(struct hdd_adapter *adapter,
575 						   struct stsf *ptsf)
576 {
577 }
578 #else
579 
580 static inline int hdd_tsf_reg_is_details_valid(struct hdd_adapter *adapter)
581 {
582 	return qdf_atomic_read(&adapter->tsf_details_valid);
583 }
584 
585 static inline void
586 wlan_hdd_tsf_reg_update_details(struct hdd_adapter *adapter, struct stsf *ptsf)
587 {
588 	if (!qdf_atomic_read(&adapter->tsf_details_valid)) {
589 		if (ptsf->tsf_id_valid) {
590 			adapter->tsf_id = ptsf->tsf_id;
591 			adapter->tsf_mac_id = ptsf->mac_id;
592 			qdf_atomic_set(&adapter->tsf_details_valid, 1);
593 		}
594 	}
595 	hdd_info("tsf_id %u tsf_id_valid %u mac_id %u mac_id_valid %u",
596 		 ptsf->tsf_id, ptsf->tsf_id_valid, ptsf->mac_id,
597 		 ptsf->mac_id_valid);
598 }
599 
600 static inline
601 QDF_STATUS wlan_hdd_tsf_reg_get(struct hdd_adapter *adapter,
602 				struct hdd_tsf_report *tsf_report)
603 {
604 	ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC);
605 	uint64_t tsf_time = 0;
606 	uint64_t tsf_sync_soc_time = 0;
607 
608 	if (qdf_unlikely(!soc))
609 		return QDF_STATUS_E_INVAL;
610 
611 	cdp_get_tsf_time(soc, tsf_report->tsf_id, tsf_report->mac_id,
612 			 &tsf_time, &tsf_sync_soc_time);
613 
614 	/* fill in the report */
615 	tsf_report->tsf = tsf_time;
616 	tsf_report->tsf_sync_soc_time = tsf_sync_soc_time;
617 	return QDF_STATUS_SUCCESS;
618 }
619 
620 /**
621  * wlan_hdd_tsf_reg_process_report() - Process tsf report
622  * @adapter: pointer to the adapter
623  * @tsf_report: pointer to tsf report
624  *
625  * This function process the tsf report received and update tsf
626  * value received via scratch register read to adapter
627  *
628  * Return: 0 for success or 1 in case of failure
629  */
630 static enum hdd_tsf_op_result
631 wlan_hdd_tsf_reg_process_report(struct hdd_adapter *adapter,
632 				struct hdd_tsf_report *tsf_report)
633 {
634 	QDF_STATUS status;
635 	QDF_TIMER_STATE capture_req_timer_status;
636 	qdf_mc_timer_t *capture_timer;
637 
638 	if (!tsf_report->tsf && !tsf_report->tsf_sync_soc_time) {
639 		hdd_err("Invalid TSF report");
640 		return HDD_TSF_OP_FAIL;
641 	}
642 
643 	if (!hdd_tsf_is_initialized(adapter)) {
644 		hdd_err("tsf is not init, ignore tsf event");
645 		return HDD_TSF_OP_FAIL;
646 	}
647 
648 	hdd_info("device_mode is %d", adapter->device_mode);
649 
650 	capture_timer = &adapter->host_capture_req_timer;
651 	capture_req_timer_status =
652 		qdf_mc_timer_get_current_state(capture_timer);
653 	if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) {
654 		hdd_warn("invalid timer status");
655 		return HDD_TSF_OP_FAIL;
656 	}
657 
658 	qdf_mc_timer_stop(capture_timer);
659 	status = qdf_mc_timer_destroy(capture_timer);
660 	if (status != QDF_STATUS_SUCCESS)
661 		hdd_warn("destroy cap req timer fail, ret: %d", status);
662 
663 	adapter->cur_target_time = tsf_report->tsf;
664 	adapter->cur_tsf_sync_soc_time = tsf_report->tsf_sync_soc_time *
665 						NSEC_PER_USEC;
666 
667 	qdf_event_set(&tsf_sync_get_completion_evt);
668 	hdd_update_tsf(adapter, adapter->cur_target_time);
669 	hdd_info("vdev id=%u, tsf=%llu", adapter->vdev_id, tsf_report->tsf);
670 	return HDD_TSF_OP_SUCC;
671 }
672 
673 static enum hdd_tsf_op_result
674 hdd_capture_tsf_internal_via_reg(struct hdd_adapter *adapter, uint32_t *buf,
675 				 int len)
676 {
677 	struct hdd_tsf_report tsf_report;
678 
679 	if (!hdd_tsf_reg_is_details_valid(adapter)) {
680 		hdd_warn("TSF reg details are not valid!");
681 		return HDD_TSF_OP_FAIL;
682 	}
683 
684 	qdf_mem_zero(&tsf_report, sizeof(tsf_report));
685 	tsf_report.vdev_id = adapter->vdev_id;
686 	tsf_report.tsf_id = adapter->tsf_id;
687 	tsf_report.mac_id = adapter->tsf_mac_id;
688 
689 	if (wlan_hdd_tsf_reg_get(adapter, &tsf_report)) {
690 		hdd_warn("Unable to get tsf report");
691 		return HDD_TSF_OP_FAIL;
692 	}
693 
694 	return wlan_hdd_tsf_reg_process_report(adapter, &tsf_report);
695 }
696 
697 static inline
698 enum hdd_tsf_op_result _hdd_capture_tsf_internal(struct hdd_adapter *adapter,
699 						 uint32_t *buf, int len)
700 {
701 	if (!qdf_atomic_read(&adapter->tsf_details_valid))
702 		return hdd_capture_tsf_internal_via_wmi(adapter, buf, len);
703 	else
704 		return hdd_capture_tsf_internal_via_reg(adapter, buf, len);
705 }
706 
707 #endif /* QCA_GET_TSF_VIA_REG */
708 
709 static enum hdd_tsf_op_result hdd_capture_tsf_internal(
710 	struct hdd_adapter *adapter, uint32_t *buf, int len)
711 {
712 	enum hdd_tsf_op_result ret;
713 	struct hdd_context *hddctx;
714 	qdf_mc_timer_t *cap_timer;
715 
716 	if (!adapter || !buf) {
717 		hdd_err("invalid pointer");
718 		return HDD_TSF_OP_FAIL;
719 	}
720 
721 	if (len != 1)
722 		return HDD_TSF_OP_FAIL;
723 
724 	hddctx = WLAN_HDD_GET_CTX(adapter);
725 	if (!hddctx) {
726 		hdd_err("invalid hdd context");
727 		return HDD_TSF_OP_FAIL;
728 	}
729 
730 	if (wlan_hdd_validate_context(hddctx)) {
731 		hdd_err("hdd context validation failed");
732 		return HDD_TSF_OP_FAIL;
733 	}
734 
735 	if (!hdd_tsf_is_initialized(adapter)) {
736 		buf[0] = TSF_NOT_READY;
737 		return HDD_TSF_OP_SUCC;
738 	}
739 
740 	buf[0] = hdd_tsf_check_conn_state(adapter);
741 	if (buf[0] != TSF_RETURN)
742 		return HDD_TSF_OP_SUCC;
743 
744 	if (qdf_atomic_inc_return(&hddctx->cap_tsf_flag) > 1) {
745 		hdd_err("current in capture state");
746 		buf[0] = TSF_CURRENT_IN_CAP_STATE;
747 		return HDD_TSF_OP_SUCC;
748 	}
749 
750 	/* record adapter for cap_tsf_irq_handler  */
751 	hddctx->cap_tsf_context = adapter;
752 
753 	hdd_info("+ioctl issue cap tsf cmd");
754 	cap_timer = &adapter->host_capture_req_timer;
755 	qdf_mc_timer_init(cap_timer, QDF_TIMER_TYPE_SW,
756 			  hdd_capture_req_timer_expired_handler,
757 			  (void *)adapter);
758 	qdf_mc_timer_start(cap_timer, WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS);
759 
760 	/* Reset TSF value for new capture */
761 	adapter->cur_target_time = 0;
762 
763 	buf[0] = TSF_RETURN;
764 
765 	if (hdd_tsf_cap_sync_send(adapter))
766 		return HDD_TSF_OP_SUCC;
767 
768 	ret = _hdd_capture_tsf_internal(adapter, buf, len);
769 	hdd_info("-ioctl return cap tsf cmd");
770 
771 	return ret;
772 }
773 
774 static enum hdd_tsf_op_result hdd_indicate_tsf_internal(
775 	struct hdd_adapter *adapter, struct hdd_tsf_op_response *tsf_op_resp)
776 {
777 	int ret;
778 	struct hdd_context *hddctx;
779 
780 	if (!adapter || !tsf_op_resp) {
781 		hdd_err("invalid pointer");
782 		return HDD_TSF_OP_FAIL;
783 	}
784 
785 	hddctx = WLAN_HDD_GET_CTX(adapter);
786 	if (!hddctx) {
787 		hdd_err("invalid hdd context");
788 		return HDD_TSF_OP_FAIL;
789 	}
790 
791 	memset(tsf_op_resp, 0, sizeof(*tsf_op_resp));
792 	if (!hdd_tsf_is_initialized(adapter)) {
793 		tsf_op_resp->status = TSF_NOT_READY;
794 		return HDD_TSF_OP_SUCC;
795 	}
796 
797 	tsf_op_resp->status = hdd_tsf_check_conn_state(adapter);
798 	if (tsf_op_resp->status != TSF_RETURN)
799 		return HDD_TSF_OP_SUCC;
800 
801 	if (adapter->cur_target_time == 0) {
802 		hdd_info("TSF value not received");
803 		tsf_op_resp->status = TSF_NOT_RETURNED_BY_FW;
804 		return HDD_TSF_OP_SUCC;
805 	}
806 
807 	tsf_op_resp->status = TSF_RETURN;
808 	tsf_op_resp->time = adapter->cur_target_time;
809 	tsf_op_resp->soc_time = adapter->cur_tsf_sync_soc_time;
810 
811 	if (!qdf_atomic_read(&hddctx->cap_tsf_flag)) {
812 		hdd_info("old: status=%u, tsf_time=%llu, tsf_soc_time=%llu",
813 			 tsf_op_resp->status,
814 			 tsf_op_resp->time,
815 			 tsf_op_resp->soc_time);
816 		return HDD_TSF_OP_SUCC;
817 	}
818 
819 	ret = hdd_tsf_reset_gpio(adapter);
820 	if (0 != ret) {
821 		hdd_err("reset tsf gpio fail");
822 		tsf_op_resp->status = TSF_RESET_GPIO_FAIL;
823 		return HDD_TSF_OP_SUCC;
824 	}
825 	hddctx->cap_tsf_context = NULL;
826 	qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
827 	hdd_info("get tsf cmd,status=%u, tsf_time=%llu, tsf_soc_time=%llu",
828 		 tsf_op_resp->status,
829 							tsf_op_resp->time,
830 							tsf_op_resp->soc_time);
831 
832 	return HDD_TSF_OP_SUCC;
833 }
834 
835 #ifdef WLAN_FEATURE_TSF_PLUS
836 /* unit for target time: us;  host time: ns */
837 #define HOST_TO_TARGET_TIME_RATIO NSEC_PER_USEC
838 #define MAX_ALLOWED_DEVIATION_NS (100 * NSEC_PER_USEC)
839 #define MAX_CONTINUOUS_ERROR_CNT 3
840 
841 /* to distinguish 32-bit overflow case, this interval should:
842  * equal or less than (1/2 * OVERFLOW_INDICATOR32 us)
843  */
844 #if defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ) || \
845 	defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
846 #define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 2
847 #else
848 #define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 4
849 #endif
850 #define OVERFLOW_INDICATOR32 (((int64_t)0x1) << 32)
851 #define CAP_TSF_TIMER_FIX_SEC 1
852 
853 /**
854  * TS_STATUS - timestamp status
855  *
856  * HDD_TS_STATUS_WAITING:  one of the stamp-pair
857  *    is not updated
858  * HDD_TS_STATUS_READY:  valid tstamp-pair
859  * HDD_TS_STATUS_INVALID: invalid tstamp-pair
860  */
861 enum hdd_ts_status {
862 	HDD_TS_STATUS_WAITING,
863 	HDD_TS_STATUS_READY,
864 	HDD_TS_STATUS_INVALID
865 };
866 
867 static
868 enum hdd_tsf_op_result __hdd_start_tsf_sync(struct hdd_adapter *adapter)
869 {
870 	QDF_STATUS ret;
871 
872 	if (!hdd_get_th_sync_status(adapter)) {
873 		hdd_err("Host Target sync has not initialized");
874 		return HDD_TSF_OP_FAIL;
875 	}
876 
877 	hdd_tsf_gpio_sync_work_init(adapter);
878 	ret = qdf_mc_timer_start(&adapter->host_target_sync_timer,
879 				 WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS);
880 	if (ret != QDF_STATUS_SUCCESS && ret != QDF_STATUS_E_ALREADY) {
881 		hdd_err("Failed to start timer, ret: %d", ret);
882 		return HDD_TSF_OP_FAIL;
883 	}
884 	return HDD_TSF_OP_SUCC;
885 }
886 
887 static
888 enum hdd_tsf_op_result __hdd_stop_tsf_sync(struct hdd_adapter *adapter)
889 {
890 	QDF_STATUS ret;
891 	struct hdd_context *hdd_ctx;
892 
893 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
894 	if (!hdd_ctx) {
895 		hdd_err("invalid hdd context");
896 		return HDD_TSF_OP_FAIL;
897 	}
898 
899 	if (!hdd_get_th_sync_status(adapter)) {
900 		hdd_err("Host Target sync has not initialized");
901 		return HDD_TSF_OP_SUCC;
902 	}
903 
904 	ret = qdf_mc_timer_stop(&adapter->host_target_sync_timer);
905 	if (ret != QDF_STATUS_SUCCESS) {
906 		hdd_err("Failed to stop timer, ret: %d", ret);
907 		return HDD_TSF_OP_FAIL;
908 	}
909 	hdd_tsf_stop_ext_gpio_sync(adapter);
910 	hdd_tsf_gpio_sync_work_deinit(adapter);
911 	return HDD_TSF_OP_SUCC;
912 }
913 
914 static inline void hdd_reset_timestamps(struct hdd_adapter *adapter)
915 {
916 	qdf_spin_lock_bh(&adapter->host_target_sync_lock);
917 	adapter->cur_host_time = 0;
918 	adapter->cur_target_time = 0;
919 	adapter->last_host_time = 0;
920 	adapter->last_target_time = 0;
921 	qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
922 }
923 
924 /**
925  * hdd_check_timestamp_status() - return the tstamp status
926  *
927  * @last_target_time: the last saved target time
928  * @last_sync_time: the last saved sync time
929  * @cur_target_time : new target time
930  * @cur_sync_time : new sync time
931  *
932  * This function check the new timstamp-pair(cur_host_time/cur_target_time)or
933  * (cur_qtime_time/cur_target_time)
934  * Return:
935  * HDD_TS_STATUS_WAITING: cur_sync_time or cur_sync_time is 0
936  * HDD_TS_STATUS_READY: cur_target_time/cur_host_time is a valid pair,
937  *    and can be saved
938  * HDD_TS_STATUS_INVALID: cur_target_time/cur_sync_time is a invalid pair,
939  *    should be discard
940  */
941 static
942 enum hdd_ts_status hdd_check_timestamp_status(
943 		uint64_t last_target_time,
944 		uint64_t last_sync_time,
945 		uint64_t cur_target_time,
946 		uint64_t cur_sync_time)
947 {
948 	uint64_t delta_ns, delta_target_time, delta_sync_time;
949 
950 	/* one or more are not updated, need to wait */
951 	if (cur_target_time == 0 || cur_sync_time == 0)
952 		return HDD_TS_STATUS_WAITING;
953 
954 	/* init value, it's the first time to update the pair */
955 	if (last_target_time == 0 && last_sync_time == 0)
956 		return HDD_TS_STATUS_READY;
957 
958 	/* the new values should be greater than the saved values */
959 	if ((cur_target_time <= last_target_time) ||
960 	    (cur_sync_time <= last_sync_time)) {
961 		hdd_err("Invalid timestamps!last_target_time: %llu;"
962 			"last_sync_time: %llu; cur_target_time: %llu;"
963 			"cur_sync_time: %llu",
964 			last_target_time, last_sync_time,
965 			cur_target_time, cur_sync_time);
966 		return HDD_TS_STATUS_INVALID;
967 	}
968 
969 	delta_target_time = (cur_target_time - last_target_time) *
970 						NSEC_PER_USEC;
971 	delta_sync_time = cur_sync_time - last_sync_time;
972 
973 	/*
974 	 * DO NOT use abs64() , a big uint64 value might be turned to
975 	 * a small int64 value
976 	 */
977 	delta_ns = ((delta_target_time > delta_sync_time) ?
978 			(delta_target_time - delta_sync_time) :
979 			(delta_sync_time - delta_target_time));
980 	hdd_warn("timestamps deviation - delta: %llu ns", delta_ns);
981 	/* the deviation should be smaller than a threshold */
982 	if (delta_ns > MAX_ALLOWED_DEVIATION_NS) {
983 		hdd_warn("Invalid timestamps - delta: %llu ns", delta_ns);
984 		return HDD_TS_STATUS_INVALID;
985 	}
986 	return HDD_TS_STATUS_READY;
987 }
988 
989 static inline bool hdd_tsf_is_in_cap(struct hdd_adapter *adapter)
990 {
991 	struct hdd_context *hddctx;
992 
993 	hddctx = WLAN_HDD_GET_CTX(adapter);
994 	if (!hddctx)
995 		return false;
996 
997 	return qdf_atomic_read(&hddctx->cap_tsf_flag) > 0;
998 }
999 
1000 /* define 64bit plus/minus to deal with overflow */
1001 static inline int hdd_64bit_plus(uint64_t x, int64_t y, uint64_t *ret)
1002 {
1003 	if ((y < 0 && (-y) > x) ||
1004 	    (y > 0 && (y > U64_MAX - x))) {
1005 		*ret = 0;
1006 		return -EINVAL;
1007 	}
1008 
1009 	*ret = x + y;
1010 	return 0;
1011 }
1012 
1013 static inline int hdd_uint64_plus(uint64_t x, uint64_t y, uint64_t *ret)
1014 {
1015 	if (!ret)
1016 		return -EINVAL;
1017 
1018 	if (x > (U64_MAX - y)) {
1019 		*ret = 0;
1020 		return -EINVAL;
1021 	}
1022 
1023 	*ret = x + y;
1024 	return 0;
1025 }
1026 
1027 static inline int hdd_uint64_minus(uint64_t x, uint64_t y, uint64_t *ret)
1028 {
1029 	if (!ret)
1030 		return -EINVAL;
1031 
1032 	if (x < y) {
1033 		*ret = 0;
1034 		return -EINVAL;
1035 	}
1036 
1037 	*ret = x - y;
1038 	return 0;
1039 }
1040 
1041 static inline int32_t hdd_get_hosttime_from_targettime(
1042 	struct hdd_adapter *adapter, uint64_t target_time,
1043 	uint64_t *host_time)
1044 {
1045 	int32_t ret = -EINVAL;
1046 	int64_t delta32_target;
1047 	bool in_cap_state;
1048 	int64_t normal_interval_target;
1049 
1050 	in_cap_state = hdd_tsf_is_in_cap(adapter);
1051 
1052 	/*
1053 	 * To avoid check the lock when it's not capturing tsf
1054 	 * (the tstamp-pair won't be changed)
1055 	 */
1056 	if (in_cap_state)
1057 		qdf_spin_lock_bh(&adapter->host_target_sync_lock);
1058 
1059 	hdd_wlan_restart_tsf_cap(adapter);
1060 	/* at present, target_time is only 32bit in fact */
1061 	delta32_target = (int64_t)((target_time & U32_MAX) -
1062 			(adapter->last_target_time & U32_MAX));
1063 
1064 	normal_interval_target = WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC *
1065 		qdf_do_div(NSEC_PER_SEC, HOST_TO_TARGET_TIME_RATIO);
1066 
1067 	if (delta32_target <
1068 			(normal_interval_target - OVERFLOW_INDICATOR32))
1069 		delta32_target += OVERFLOW_INDICATOR32;
1070 	else if (delta32_target >
1071 			(OVERFLOW_INDICATOR32 - normal_interval_target))
1072 		delta32_target -= OVERFLOW_INDICATOR32;
1073 
1074 	ret = hdd_64bit_plus(adapter->last_host_time,
1075 			     HOST_TO_TARGET_TIME_RATIO * delta32_target,
1076 			     host_time);
1077 
1078 	if (in_cap_state)
1079 		qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
1080 
1081 	return ret;
1082 }
1083 
1084 static inline int32_t hdd_get_targettime_from_hosttime(
1085 	struct hdd_adapter *adapter, uint64_t host_time,
1086 	uint64_t *target_time)
1087 {
1088 	int32_t ret = -EINVAL;
1089 	bool in_cap_state;
1090 
1091 	if (!adapter || host_time == 0)
1092 		return ret;
1093 
1094 	in_cap_state = hdd_tsf_is_in_cap(adapter);
1095 	if (in_cap_state)
1096 		qdf_spin_lock_bh(&adapter->host_target_sync_lock);
1097 
1098 	if (host_time < adapter->last_host_time)
1099 		ret = hdd_uint64_minus(adapter->last_target_time,
1100 				       qdf_do_div(adapter->last_host_time -
1101 						  host_time,
1102 						  HOST_TO_TARGET_TIME_RATIO),
1103 				       target_time);
1104 	else
1105 		ret = hdd_uint64_plus(adapter->last_target_time,
1106 				      qdf_do_div(host_time -
1107 						 adapter->last_host_time,
1108 						 HOST_TO_TARGET_TIME_RATIO),
1109 				      target_time);
1110 
1111 	if (in_cap_state)
1112 		qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
1113 
1114 	return ret;
1115 }
1116 
1117 /**
1118  * hdd_get_soctime_from_tsf64time() - return get status
1119  *
1120  * @adapter: Adapter pointer
1121  * @tsf64_time: current tsf64time, us
1122  * @soc_time: current soc time(qtime), ns
1123  *
1124  * This function get current soc time from current tsf64 time
1125  * Returun int32_t value to tell get success or fail.
1126  *
1127  * Return:
1128  * 0:        success
1129  * other: fail
1130  *
1131  */
1132 static inline int32_t hdd_get_soctime_from_tsf64time(
1133 	struct hdd_adapter *adapter, uint64_t tsf64_time,
1134 	uint64_t *soc_time)
1135 {
1136 	int32_t ret = -EINVAL;
1137 	uint64_t delta64_tsf64time;
1138 	uint64_t delta64_soctime;
1139 	bool in_cap_state;
1140 
1141 	in_cap_state = hdd_tsf_is_in_cap(adapter);
1142 
1143 	/*
1144 	 * To avoid check the lock when it's not capturing tsf
1145 	 * (the tstamp-pair won't be changed)
1146 	 */
1147 	if (in_cap_state)
1148 		qdf_spin_lock_bh(&adapter->host_target_sync_lock);
1149 
1150 	/* at present, target_time is 64bit (g_tsf64), us*/
1151 	if (tsf64_time > adapter->last_target_global_tsf_time) {
1152 		delta64_tsf64time = tsf64_time -
1153 				    adapter->last_target_global_tsf_time;
1154 		delta64_soctime = delta64_tsf64time * NSEC_PER_USEC;
1155 
1156 		/* soc_time (ns)*/
1157 		ret = hdd_uint64_plus(adapter->last_tsf_sync_soc_time,
1158 				      delta64_soctime, soc_time);
1159 	} else {
1160 		delta64_tsf64time = adapter->last_target_global_tsf_time -
1161 				    tsf64_time;
1162 		delta64_soctime = delta64_tsf64time * NSEC_PER_USEC;
1163 
1164 		/* soc_time (ns)*/
1165 		ret = hdd_uint64_minus(adapter->last_tsf_sync_soc_time,
1166 				       delta64_soctime, soc_time);
1167 	}
1168 
1169 	if (in_cap_state)
1170 		qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
1171 
1172 	return ret;
1173 }
1174 
1175 /**
1176  * hdd_get_tsftime_from_qtime()
1177  *
1178  * @adapter: Adapter pointer
1179  * @qtime: current qtime, us
1180  * @tsf_sync_qtime: qtime of the tsf, us
1181  * @tsf_time: current tsf time(qtime), us
1182  *
1183  * This function determines current tsf time
1184  * using current qtime
1185  *
1186  * Return: 0 for success or non-zero negative failure code
1187  */
1188 static inline int32_t
1189 hdd_get_tsftime_from_qtime(struct hdd_adapter *adapter, uint64_t qtime,
1190 			   uint64_t tsf_sync_qtime, uint64_t *tsf_time)
1191 {
1192 	int32_t ret = -EINVAL;
1193 	uint64_t delta64_tsf64time;
1194 	bool in_cap_state;
1195 
1196 	in_cap_state = hdd_tsf_is_in_cap(adapter);
1197 
1198 	/*
1199 	 * To avoid check the lock when it's not capturing tsf
1200 	 * (the tstamp-pair won't be changed)
1201 	 */
1202 	if (in_cap_state)
1203 		qdf_spin_lock_bh(&adapter->host_target_sync_lock);
1204 
1205 	if (qtime > tsf_sync_qtime) {
1206 		delta64_tsf64time = qtime - tsf_sync_qtime;
1207 		ret = hdd_uint64_plus(adapter->last_target_time,
1208 				      delta64_tsf64time, tsf_time);
1209 	} else {
1210 		delta64_tsf64time = tsf_sync_qtime - qtime;
1211 		ret = hdd_uint64_minus(adapter->last_target_time,
1212 				       delta64_tsf64time, tsf_time);
1213 	}
1214 
1215 	if (in_cap_state)
1216 		qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
1217 
1218 	return ret;
1219 }
1220 
1221 QDF_STATUS hdd_get_tsf_time(void *adapter_ctx, uint64_t input_time,
1222 			    uint64_t *tsf_time)
1223 {
1224 	struct hdd_adapter *adapter;
1225 	uint64_t tsf_sync_qtime, qtime;
1226 
1227 	/* Sanity check on inputs */
1228 	if (unlikely((!adapter_ctx) || (!input_time))) {
1229 		hdd_err("Invalid param passed");
1230 		return QDF_STATUS_E_FAILURE;
1231 	}
1232 
1233 	adapter = (struct hdd_adapter *)adapter_ctx;
1234 	if (unlikely(adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) {
1235 		hdd_err("Magic cookie(%x) for adapter sanity verification is invalid",
1236 			adapter->magic);
1237 		return QDF_STATUS_E_FAILURE;
1238 	}
1239 
1240 	tsf_sync_qtime = adapter->last_tsf_sync_soc_time;
1241 	tsf_sync_qtime = qdf_do_div(tsf_sync_qtime, NSEC_PER_USEC);
1242 
1243 	qtime = qdf_log_timestamp_to_usecs(input_time);
1244 	hdd_get_tsftime_from_qtime(adapter, qtime, tsf_sync_qtime, tsf_time);
1245 	return QDF_STATUS_SUCCESS;
1246 }
1247 
1248 static void hdd_capture_tsf_timer_expired_handler(void *arg)
1249 {
1250 	uint32_t tsf_op_resp;
1251 	struct hdd_adapter *adapter;
1252 
1253 	if (!arg)
1254 		return;
1255 
1256 	adapter = (struct hdd_adapter *)arg;
1257 	hdd_capture_tsf_internal(adapter, &tsf_op_resp, 1);
1258 }
1259 
1260 #ifndef WLAN_FEATURE_TSF_PLUS_NOIRQ
1261 #if !defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) && \
1262 	!defined(WLAN_FEATURE_TSF_TIMER_SYNC)
1263 
1264 static irqreturn_t hdd_tsf_captured_irq_handler(int irq, void *arg)
1265 {
1266 	struct hdd_adapter *adapter;
1267 	struct hdd_context *hdd_ctx;
1268 	uint64_t host_time;
1269 	char *name = NULL;
1270 
1271 	if (!arg)
1272 		return IRQ_NONE;
1273 
1274 	if (irq != tsf_gpio_irq_num)
1275 		return IRQ_NONE;
1276 
1277 	hdd_ctx = (struct hdd_context *)arg;
1278 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
1279 
1280 	adapter = hdd_ctx->cap_tsf_context;
1281 	if (!adapter)
1282 		return IRQ_HANDLED;
1283 
1284 	if (!hdd_tsf_is_initialized(adapter)) {
1285 		hdd_err("tsf is not init, ignore irq");
1286 		return IRQ_HANDLED;
1287 	}
1288 
1289 	hdd_update_timestamp(adapter, 0, host_time);
1290 	if (adapter->dev)
1291 		name = adapter->dev->name;
1292 
1293 	hdd_info("irq: %d - iface: %s - host_time: %llu",
1294 		 irq, (!name ? "none" : name), host_time);
1295 
1296 	return IRQ_HANDLED;
1297 }
1298 #endif
1299 #endif
1300 
1301 void hdd_capture_req_timer_expired_handler(void *arg)
1302 {
1303 	struct hdd_adapter *adapter;
1304 	struct hdd_context *hdd_ctx;
1305 	QDF_TIMER_STATE capture_req_timer_status;
1306 	qdf_mc_timer_t *sync_timer;
1307 	int interval;
1308 	int ret;
1309 
1310 	if (!arg)
1311 		return;
1312 	adapter = (struct hdd_adapter *)arg;
1313 
1314 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1315 	if (!hdd_ctx) {
1316 		hdd_warn("invalid hdd context");
1317 		return;
1318 	}
1319 
1320 	if (!hdd_tsf_is_initialized(adapter)) {
1321 		qdf_mc_timer_destroy(&adapter->host_capture_req_timer);
1322 		hdd_warn("tsf not init");
1323 		return;
1324 	}
1325 
1326 	qdf_spin_lock_bh(&adapter->host_target_sync_lock);
1327 	adapter->cur_host_time = 0;
1328 	adapter->cur_target_time = 0;
1329 	qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
1330 
1331 	ret = hdd_tsf_reset_gpio(adapter);
1332 	if (0 != ret)
1333 		hdd_info("reset tsf gpio fail");
1334 
1335 	hdd_ctx->cap_tsf_context = NULL;
1336 	qdf_atomic_set(&hdd_ctx->cap_tsf_flag, 0);
1337 	qdf_mc_timer_destroy(&adapter->host_capture_req_timer);
1338 
1339 	sync_timer = &adapter->host_target_sync_timer;
1340 	capture_req_timer_status =
1341 		qdf_mc_timer_get_current_state(sync_timer);
1342 
1343 	if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) {
1344 		hdd_warn("invalid timer status");
1345 		return;
1346 	}
1347 
1348 	interval = WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL * MSEC_PER_SEC;
1349 	qdf_mc_timer_start(sync_timer, interval);
1350 }
1351 
1352 #if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) || \
1353 	defined(WLAN_FEATURE_TSF_TIMER_SYNC)
1354 static void hdd_update_timestamp(struct hdd_adapter *adapter)
1355 {
1356 	int interval = 0;
1357 	enum hdd_ts_status sync_status;
1358 
1359 	if (!adapter)
1360 		return;
1361 
1362 	/* on ADREASTEA ach, Qtime is used to sync host and tsf time as a
1363 	 * intermedia there is no IRQ to sync up TSF-HOST, so host time in ns
1364 	 * and target in us will be updated at the same time in WMI command
1365 	 * callback
1366 	 */
1367 
1368 	qdf_spin_lock_bh(&adapter->host_target_sync_lock);
1369 	sync_status =
1370 		  hdd_check_timestamp_status(adapter->last_target_time,
1371 					     adapter->last_tsf_sync_soc_time,
1372 					     adapter->cur_target_time,
1373 					     adapter->cur_tsf_sync_soc_time);
1374 	hdd_info("sync_status %d", sync_status);
1375 	switch (sync_status) {
1376 	case HDD_TS_STATUS_INVALID:
1377 		if (++adapter->continuous_error_count <
1378 		    MAX_CONTINUOUS_ERROR_CNT) {
1379 			interval =
1380 				WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS;
1381 			adapter->cur_target_time = 0;
1382 			adapter->cur_tsf_sync_soc_time = 0;
1383 			break;
1384 		}
1385 		hdd_warn("Reach the max continuous error count");
1386 
1387 		/* If reach MAX_CONTINUOUS_ERROR_CNT, treat it as valid pair */
1388 		fallthrough;
1389 	case HDD_TS_STATUS_READY:
1390 		adapter->last_target_time = adapter->cur_target_time;
1391 		adapter->last_target_global_tsf_time =
1392 			adapter->cur_target_global_tsf_time;
1393 		adapter->last_tsf_sync_soc_time =
1394 				adapter->cur_tsf_sync_soc_time;
1395 		adapter->cur_target_time = 0;
1396 		adapter->cur_target_global_tsf_time = 0;
1397 		adapter->cur_tsf_sync_soc_time = 0;
1398 		hdd_info("ts-pair updated: target: %llu; g_target:%llu, Qtime: %llu",
1399 			 adapter->last_target_time,
1400 			 adapter->last_target_global_tsf_time,
1401 			 adapter->last_tsf_sync_soc_time);
1402 
1403 		/*
1404 		 * TSF-HOST need to be updated in at most
1405 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, it couldn't be achieved
1406 		 * if the timer interval is also
1407 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, due to processing or
1408 		 * schedule delay. So deduct several seconds from
1409 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC.
1410 		 * Without this change, hdd_get_hosttime_from_targettime() will
1411 		 * get wrong host time when it's longer than
1412 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last
1413 		 * TSF-HOST update.
1414 		 */
1415 
1416 		if (adapter->dynamic_tsf_sync_interval)
1417 			interval = adapter->dynamic_tsf_sync_interval;
1418 		else
1419 			interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC -
1420 				    CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC;
1421 
1422 		adapter->continuous_error_count = 0;
1423 		adapter->continuous_cap_retry_count = 0;
1424 		hdd_debug("ts-pair updated: interval: %d",
1425 			  interval);
1426 		break;
1427 	case HDD_TS_STATUS_WAITING:
1428 		interval = 0;
1429 		hdd_warn("TS status is waiting due to one or more pair not updated");
1430 		break;
1431 	}
1432 	qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
1433 
1434 	if (interval > 0)
1435 		qdf_mc_timer_start(&adapter->host_target_sync_timer, interval);
1436 }
1437 
1438 static ssize_t __hdd_wlan_tsf_show(struct device *dev,
1439 				   struct device_attribute *attr, char *buf)
1440 {
1441 	struct hdd_station_ctx *hdd_sta_ctx;
1442 	struct hdd_adapter *adapter;
1443 	struct hdd_context *hdd_ctx;
1444 	uint64_t tsf_sync_qtime, host_time, reg_qtime, qtime, target_time;
1445 	ssize_t size;
1446 
1447 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
1448 
1449 	adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
1450 	if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC)
1451 		return scnprintf(buf, PAGE_SIZE, "Invalid device\n");
1452 
1453 	if (!hdd_get_th_sync_status(adapter))
1454 		return scnprintf(buf, PAGE_SIZE,
1455 				 "TSF sync is not initialized\n");
1456 
1457 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1458 	if (!hdd_cm_is_vdev_associated(adapter) &&
1459 	    (adapter->device_mode == QDF_STA_MODE ||
1460 	    adapter->device_mode == QDF_P2P_CLIENT_MODE))
1461 		return scnprintf(buf, PAGE_SIZE, "NOT connected\n");
1462 
1463 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1464 
1465 	if (!hdd_ctx)
1466 		return scnprintf(buf, PAGE_SIZE, "Invalid HDD context\n");
1467 
1468 	tsf_sync_qtime = adapter->last_tsf_sync_soc_time;
1469 	do_div(tsf_sync_qtime, NSEC_PER_USEC);
1470 
1471 	reg_qtime = qdf_get_log_timestamp();
1472 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
1473 
1474 	qtime = qdf_log_timestamp_to_usecs(reg_qtime);
1475 	do_div(host_time, NSEC_PER_USEC);
1476 	hdd_get_tsftime_from_qtime(adapter, qtime, tsf_sync_qtime,
1477 				   &target_time);
1478 
1479 	if (adapter->device_mode == QDF_STA_MODE ||
1480 	    adapter->device_mode == QDF_P2P_CLIENT_MODE) {
1481 		size = scnprintf(buf, PAGE_SIZE,
1482 				 "%s%llu %llu %pM %llu %llu %llu\n",
1483 				 buf, adapter->last_target_time,
1484 				 tsf_sync_qtime,
1485 				 hdd_sta_ctx->conn_info.bssid.bytes,
1486 				 qtime, host_time, target_time);
1487 	} else {
1488 		size = scnprintf(buf, PAGE_SIZE,
1489 				 "%s%llu %llu %pM %llu %llu %llu\n",
1490 				 buf, adapter->last_target_time,
1491 				 tsf_sync_qtime,
1492 				 adapter->mac_addr.bytes,
1493 				 qtime, host_time, target_time);
1494 	}
1495 
1496 	return size;
1497 }
1498 
1499 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
1500 {
1501 	struct hdd_tsf_op_response tsf_op_resp;
1502 
1503 	hdd_indicate_tsf_internal(adapter, &tsf_op_resp);
1504 	hdd_update_timestamp(adapter);
1505 }
1506 #else
1507 static void hdd_update_timestamp(struct hdd_adapter *adapter,
1508 				 uint64_t target_time, uint64_t host_time)
1509 {
1510 	int interval = 0;
1511 	enum hdd_ts_status sync_status;
1512 
1513 	if (!adapter)
1514 		return;
1515 
1516 	/* host time is updated in IRQ context, it's always before target time,
1517 	 * and so no need to try update last_host_time at present;
1518 	 * since the interval of capturing TSF
1519 	 * (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC) is long enough, host and target
1520 	 * time are updated in pairs, and one by one, we can return here to
1521 	 * avoid requiring spin lock, and to speed up the IRQ processing.
1522 	 */
1523 	if (host_time > 0)
1524 		adapter->cur_host_time = host_time;
1525 
1526 	qdf_spin_lock_bh(&adapter->host_target_sync_lock);
1527 	if (target_time > 0)
1528 		adapter->cur_target_time = target_time;
1529 
1530 	sync_status = hdd_check_timestamp_status(adapter->last_target_time,
1531 						 adapter->last_host_time,
1532 						 adapter->cur_target_time,
1533 						 adapter->cur_host_time);
1534 	hdd_info("sync_status %d", sync_status);
1535 	switch (sync_status) {
1536 	case HDD_TS_STATUS_INVALID:
1537 		if (++adapter->continuous_error_count <
1538 		    MAX_CONTINUOUS_ERROR_CNT) {
1539 			interval =
1540 				WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS;
1541 			adapter->cur_target_time = 0;
1542 			adapter->cur_host_time = 0;
1543 			break;
1544 		}
1545 		hdd_warn("Reach the max continuous error count");
1546 		/*
1547 		 * fall through:
1548 		 * If reach MAX_CONTINUOUS_ERROR_CNT, treat it as a
1549 		 * valid pair
1550 		 */
1551 	case HDD_TS_STATUS_READY:
1552 		adapter->last_target_time = adapter->cur_target_time;
1553 		adapter->last_host_time = adapter->cur_host_time;
1554 		adapter->cur_target_time = 0;
1555 		adapter->cur_host_time = 0;
1556 		hdd_info("ts-pair updated: target: %llu; host: %llu",
1557 			 adapter->last_target_time,
1558 			 adapter->last_host_time);
1559 
1560 		/*
1561 		 * TSF-HOST need to be updated in at most
1562 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, it couldn't be achieved
1563 		 * if the timer interval is also
1564 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, due to processing or
1565 		 * schedule delay. So deduct several seconds from
1566 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC.
1567 		 * Without this change, hdd_get_hosttime_from_targettime() will
1568 		 * get wrong host time when it's longer than
1569 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last
1570 		 * TSF-HOST update.
1571 		 */
1572 		interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC -
1573 			    CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC;
1574 		if (adapter->device_mode == QDF_SAP_MODE ||
1575 		    adapter->device_mode == QDF_P2P_GO_MODE) {
1576 			interval *= WLAN_HDD_SOFTAP_INTERVAL_TIMES;
1577 		}
1578 
1579 		adapter->continuous_error_count = 0;
1580 		adapter->continuous_cap_retry_count = 0;
1581 		hdd_debug("ts-pair updated: interval: %d",
1582 			  interval);
1583 		break;
1584 	case HDD_TS_STATUS_WAITING:
1585 		interval = 0;
1586 		hdd_warn("TS status is waiting due to one or more pair not updated");
1587 
1588 		if (!target_time && !host_time)
1589 			interval = hdd_wlan_retry_tsf_cap(adapter);
1590 		break;
1591 	}
1592 	qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
1593 
1594 	if (interval > 0)
1595 		qdf_mc_timer_start(&adapter->host_target_sync_timer, interval);
1596 }
1597 
1598 static ssize_t __hdd_wlan_tsf_show(struct device *dev,
1599 				   struct device_attribute *attr, char *buf)
1600 {
1601 	struct hdd_station_ctx *hdd_sta_ctx;
1602 	struct hdd_adapter *adapter;
1603 	struct hdd_context *hdd_ctx;
1604 	ssize_t size;
1605 	uint64_t host_time, target_time;
1606 
1607 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
1608 
1609 	adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
1610 	if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC)
1611 		return scnprintf(buf, PAGE_SIZE, "Invalid device\n");
1612 
1613 	if (!hdd_get_th_sync_status(adapter))
1614 		return scnprintf(buf, PAGE_SIZE,
1615 				 "TSF sync is not initialized\n");
1616 
1617 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
1618 	if (!hdd_cm_is_vdev_associated(adapter) &&
1619 	    (adapter->device_mode == QDF_STA_MODE ||
1620 	    adapter->device_mode == QDF_P2P_CLIENT_MODE))
1621 		return scnprintf(buf, PAGE_SIZE, "NOT connected\n");
1622 
1623 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1624 	if (!hdd_ctx)
1625 		return scnprintf(buf, PAGE_SIZE, "Invalid HDD context\n");
1626 
1627 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
1628 
1629 	if (hdd_get_targettime_from_hosttime(adapter, host_time,
1630 					     &target_time)) {
1631 		size = scnprintf(buf, PAGE_SIZE, "Invalid timestamp\n");
1632 	} else {
1633 		if (adapter->device_mode == QDF_STA_MODE ||
1634 		    adapter->device_mode == QDF_P2P_CLIENT_MODE) {
1635 			size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM\n",
1636 					 buf, target_time, host_time,
1637 					 hdd_sta_ctx->conn_info.bssid.bytes);
1638 		} else {
1639 			size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM\n",
1640 					 buf, target_time, host_time,
1641 					 adapter->mac_addr.bytes);
1642 		}
1643 	}
1644 
1645 	return size;
1646 }
1647 
1648 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
1649 {
1650 	struct hdd_tsf_op_response tsf_op_resp;
1651 
1652 	hdd_indicate_tsf_internal(adapter, &tsf_op_resp);
1653 	hdd_update_timestamp(adapter, tsf, 0);
1654 }
1655 #endif
1656 
1657 static ssize_t hdd_wlan_tsf_show(struct device *dev,
1658 				 struct device_attribute *attr, char *buf)
1659 {
1660 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
1661 	struct osif_vdev_sync *vdev_sync;
1662 	ssize_t err_size;
1663 
1664 	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
1665 	if (err_size)
1666 		return err_size;
1667 
1668 	err_size = __hdd_wlan_tsf_show(dev, attr, buf);
1669 
1670 	osif_vdev_sync_op_stop(vdev_sync);
1671 
1672 	return err_size;
1673 }
1674 
1675 static DEVICE_ATTR(tsf, 0444, hdd_wlan_tsf_show, NULL);
1676 
1677 static enum hdd_tsf_op_result hdd_tsf_sync_init(struct hdd_adapter *adapter)
1678 {
1679 	QDF_STATUS ret;
1680 	struct hdd_context *hddctx;
1681 	struct net_device *net_dev;
1682 	uint64_t host_time, qtime;
1683 
1684 	if (!adapter)
1685 		return HDD_TSF_OP_FAIL;
1686 
1687 	hddctx = WLAN_HDD_GET_CTX(adapter);
1688 	if (!hddctx) {
1689 		hdd_err("invalid hdd context");
1690 		return HDD_TSF_OP_FAIL;
1691 	}
1692 
1693 	if (!qdf_atomic_read(&hddctx->tsf_ready_flag)) {
1694 		hdd_err("TSF feature has NOT been initialized");
1695 		return HDD_TSF_OP_FAIL;
1696 	}
1697 
1698 	if (!adapter->enable_dynamic_tsf_sync) {
1699 		hdd_debug("TSF sync feature not enabled");
1700 		return HDD_TSF_OP_FAIL;
1701 	}
1702 
1703 	if (hdd_get_th_sync_status(adapter)) {
1704 		hdd_err("Host Target sync has been initialized!!");
1705 		return HDD_TSF_OP_SUCC;
1706 	}
1707 
1708 	qdf_spinlock_create(&adapter->host_target_sync_lock);
1709 
1710 	hdd_reset_timestamps(adapter);
1711 
1712 	ret = qdf_mc_timer_init(&adapter->host_target_sync_timer,
1713 				QDF_TIMER_TYPE_SW,
1714 				hdd_capture_tsf_timer_expired_handler,
1715 				(void *)adapter);
1716 	if (ret != QDF_STATUS_SUCCESS) {
1717 		hdd_err("Failed to init timer, ret: %d", ret);
1718 		goto fail;
1719 	}
1720 
1721 	net_dev = adapter->dev;
1722 	if (net_dev && hdd_tsf_is_dbg_fs_set(hddctx))
1723 		device_create_file(&net_dev->dev, &dev_attr_tsf);
1724 	hdd_set_th_sync_status(adapter, true);
1725 
1726 	qtime = qdf_get_log_timestamp();
1727 	host_time = hdd_get_monotonic_host_time(hddctx);
1728 
1729 	qtime = qdf_log_timestamp_to_usecs(qtime);
1730 	do_div(host_time, NSEC_PER_USEC);
1731 
1732 	adapter->delta_qtime = (qtime - host_time) * NSEC_PER_USEC;
1733 
1734 	return HDD_TSF_OP_SUCC;
1735 fail:
1736 	hdd_set_th_sync_status(adapter, false);
1737 	return HDD_TSF_OP_FAIL;
1738 }
1739 
1740 static enum hdd_tsf_op_result hdd_tsf_sync_deinit(struct hdd_adapter *adapter)
1741 {
1742 	QDF_STATUS ret;
1743 	struct hdd_context *hddctx;
1744 	struct net_device *net_dev;
1745 
1746 	if (!adapter)
1747 		return HDD_TSF_OP_FAIL;
1748 
1749 	if (!hdd_get_th_sync_status(adapter))
1750 		return HDD_TSF_OP_SUCC;
1751 
1752 	hdd_set_th_sync_status(adapter, false);
1753 	ret = qdf_mc_timer_destroy(&adapter->host_target_sync_timer);
1754 	if (ret != QDF_STATUS_SUCCESS)
1755 		hdd_err("Failed to destroy timer, ret: %d", ret);
1756 
1757 	hddctx = WLAN_HDD_GET_CTX(adapter);
1758 
1759 	/* reset the cap_tsf flag and gpio if needed */
1760 	if (hddctx && qdf_atomic_read(&hddctx->cap_tsf_flag) &&
1761 	    hddctx->cap_tsf_context == adapter) {
1762 		int reset_ret = hdd_tsf_reset_gpio(adapter);
1763 
1764 		if (reset_ret)
1765 			hdd_err("Failed to reset tsf gpio, ret:%d",
1766 				reset_ret);
1767 		hddctx->cap_tsf_context = NULL;
1768 		qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
1769 	}
1770 
1771 	hdd_reset_timestamps(adapter);
1772 
1773 	net_dev = adapter->dev;
1774 	if (net_dev && hdd_tsf_is_dbg_fs_set(hddctx)) {
1775 		struct device *dev = &net_dev->dev;
1776 
1777 		device_remove_file(dev, &dev_attr_tsf);
1778 	}
1779 	return HDD_TSF_OP_SUCC;
1780 }
1781 
1782 int hdd_start_tsf_sync(struct hdd_adapter *adapter)
1783 {
1784 	enum hdd_tsf_op_result ret;
1785 
1786 	if (!adapter)
1787 		return -EINVAL;
1788 
1789 	ret = hdd_tsf_sync_init(adapter);
1790 	if (ret != HDD_TSF_OP_SUCC)
1791 		return -EINVAL;
1792 
1793 	return (__hdd_start_tsf_sync(adapter) ==
1794 		HDD_TSF_OP_SUCC) ? 0 : -EINVAL;
1795 }
1796 
1797 int hdd_stop_tsf_sync(struct hdd_adapter *adapter)
1798 {
1799 	enum hdd_tsf_op_result ret;
1800 
1801 	if (!adapter)
1802 		return -EINVAL;
1803 
1804 	ret = __hdd_stop_tsf_sync(adapter);
1805 	if (ret != HDD_TSF_OP_SUCC)
1806 		return -EINVAL;
1807 
1808 	ret = hdd_tsf_sync_deinit(adapter);
1809 	if (ret != HDD_TSF_OP_SUCC) {
1810 		hdd_err("Failed to deinit tsf sync, ret: %d", ret);
1811 		return -EINVAL;
1812 	}
1813 	return 0;
1814 }
1815 
1816 static inline int __hdd_capture_tsf(struct hdd_adapter *adapter,
1817 				    uint32_t *buf, int len)
1818 {
1819 	if (!adapter || !buf) {
1820 		hdd_err("invalid pointer");
1821 		return -EINVAL;
1822 	}
1823 
1824 	if (len != 1)
1825 		return -EINVAL;
1826 
1827 	buf[0] = TSF_DISABLED_BY_TSFPLUS;
1828 
1829 	return 0;
1830 }
1831 
1832 /**
1833  * hdd_handle_tsf_dynamic_start()
1834  * @adapter: Adapter pointer
1835  * @attr: TSF sync interval from NL interface
1836  *
1837  * This function enables TSF sync if capture mode is Dynamic set from ini
1838  *
1839  * Return: 0 for success or non-zero negative failure code
1840  */
1841 static int hdd_handle_tsf_dynamic_start(struct hdd_adapter *adapter,
1842 					struct nlattr *attr)
1843 {
1844 	struct hdd_context *hdd_ctx;
1845 	uint32_t dynamic_tsf_sync_interval = 0;
1846 
1847 	if (!adapter)
1848 		return -EINVAL;
1849 
1850 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1851 	if (wlan_hdd_validate_context(hdd_ctx))
1852 		return -EINVAL;
1853 
1854 	if (attr)
1855 		dynamic_tsf_sync_interval = nla_get_u32(attr);
1856 
1857 	if (adapter->enable_dynamic_tsf_sync) {
1858 		if (dynamic_tsf_sync_interval ==
1859 		    adapter->dynamic_tsf_sync_interval) {
1860 			return -EALREADY;
1861 		}
1862 		adapter->dynamic_tsf_sync_interval =
1863 			 dynamic_tsf_sync_interval;
1864 		return 0;
1865 	}
1866 
1867 	adapter->dynamic_tsf_sync_interval = dynamic_tsf_sync_interval;
1868 	adapter->enable_dynamic_tsf_sync = true;
1869 
1870 	return hdd_start_tsf_sync(adapter);
1871 }
1872 
1873 /**
1874  * hdd_handle_tsf_dynamic_stop()
1875  * @adapter: Adapter pointer
1876  *
1877  * This function disable TSF sync if capture mode is Dynamic set from ini
1878  *
1879  * Return: 0 for success or non-zero negative failure code
1880  */
1881 static int hdd_handle_tsf_dynamic_stop(struct hdd_adapter *adapter)
1882 {
1883 	struct hdd_context *hdd_ctx;
1884 
1885 	if (!adapter)
1886 		return -EINVAL;
1887 
1888 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1889 	if (wlan_hdd_validate_context(hdd_ctx))
1890 		return -EINVAL;
1891 
1892 	if (!adapter->enable_dynamic_tsf_sync)
1893 		return -EALREADY;
1894 
1895 	adapter->enable_dynamic_tsf_sync = false;
1896 	adapter->dynamic_tsf_sync_interval = 0;
1897 	return hdd_stop_tsf_sync(adapter);
1898 }
1899 
1900 #if defined(WLAN_FEATURE_TSF_TIMER_SYNC)
1901 static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter,
1902 						 struct hdd_tsf_op_response
1903 								*tsf_op_resp)
1904 {
1905 	if (!adapter || !tsf_op_resp) {
1906 		hdd_err("invalid pointer");
1907 		return HDD_TSF_OP_FAIL;
1908 	}
1909 
1910 	memset(tsf_op_resp, 0, sizeof(*tsf_op_resp));
1911 	if (!hdd_tsf_is_initialized(adapter)) {
1912 		tsf_op_resp->status = TSF_NOT_READY;
1913 		return HDD_TSF_OP_SUCC;
1914 	}
1915 
1916 	tsf_op_resp->status = hdd_tsf_check_conn_state(adapter);
1917 	if (tsf_op_resp->status != TSF_RETURN)
1918 		return HDD_TSF_OP_SUCC;
1919 
1920 	if (adapter->last_target_time == 0) {
1921 		hdd_info("TSF value not received");
1922 		tsf_op_resp->status = TSF_NOT_RETURNED_BY_FW;
1923 		return HDD_TSF_OP_SUCC;
1924 	}
1925 
1926 	tsf_op_resp->time = adapter->last_target_time;
1927 	tsf_op_resp->soc_time = adapter->last_tsf_sync_soc_time;
1928 
1929 	return HDD_TSF_OP_SUCC;
1930 }
1931 
1932 #else
1933 static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter,
1934 						 struct hdd_tsf_op_response
1935 								*tsf_op_resp)
1936 {
1937 	if (!adapter || !tsf_op_resp) {
1938 		hdd_err("invalid pointer");
1939 		return HDD_TSF_OP_FAIL;
1940 	}
1941 
1942 	tsf_op_resp->status = TSF_DISABLED_BY_TSFPLUS;
1943 	tsf_op_resp->time = 0;
1944 	tsf_op_resp->soc_time = 0;
1945 
1946 	return HDD_TSF_OP_SUCC;
1947 }
1948 #endif
1949 
1950 #ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS
1951 #ifdef CONFIG_HL_SUPPORT
1952 static inline
1953 enum hdd_tsf_op_result hdd_netbuf_timestamp(qdf_nbuf_t netbuf,
1954 					    uint64_t target_time)
1955 {
1956 	struct hdd_adapter *adapter;
1957 	struct net_device *net_dev = netbuf->dev;
1958 
1959 	if (!net_dev)
1960 		return HDD_TSF_OP_FAIL;
1961 
1962 	adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
1963 	if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC &&
1964 	    hdd_get_th_sync_status(adapter)) {
1965 		uint64_t host_time;
1966 		int32_t ret = hdd_get_hosttime_from_targettime(adapter,
1967 				target_time, &host_time);
1968 		if (!ret) {
1969 			netbuf->tstamp = ns_to_ktime(host_time);
1970 			return HDD_TSF_OP_SUCC;
1971 		}
1972 	}
1973 
1974 	return HDD_TSF_OP_FAIL;
1975 }
1976 
1977 #else
1978 static inline
1979 enum hdd_tsf_op_result hdd_netbuf_timestamp(qdf_nbuf_t netbuf,
1980 					    uint64_t target_time)
1981 {
1982 	struct hdd_adapter *adapter;
1983 	struct net_device *net_dev = netbuf->dev;
1984 	struct skb_shared_hwtstamps hwtstamps;
1985 
1986 	if (!net_dev)
1987 		return HDD_TSF_OP_FAIL;
1988 
1989 	adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
1990 	if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC &&
1991 	    hdd_get_th_sync_status(adapter)) {
1992 		uint64_t tsf64_time = target_time;
1993 		uint64_t soc_time = 0;/*ns*/
1994 		int32_t ret = hdd_get_soctime_from_tsf64time(adapter,
1995 				tsf64_time, &soc_time);
1996 		if (!ret) {
1997 			/* Adjust delta_qtime to soc_time(Qtime), so that
1998 			 * System Monotonic time and Qtime are in sync.
1999 			 */
2000 			if (soc_time > (adapter->delta_qtime)) {
2001 				hwtstamps.hwtstamp =
2002 				soc_time - (adapter->delta_qtime);
2003 				*skb_hwtstamps(netbuf) = hwtstamps;
2004 				netbuf->tstamp = ktime_set(0, 0);
2005 				return HDD_TSF_OP_SUCC;
2006 			} else {
2007 				return HDD_TSF_OP_FAIL;
2008 			}
2009 		}
2010 	}
2011 
2012 	return HDD_TSF_OP_FAIL;
2013 }
2014 #endif
2015 
2016 /**
2017  * hdd_tx_timestamp() - time stamp TX netbuf
2018  *
2019  * @netbuf: pointer to a TX netbuf
2020  * @target_time: TX time for the netbuf
2021  *
2022  * This function  get corresponding host time from target time,
2023  * and time stamp the TX netbuf with this time
2024  *
2025  * Return: Describe the execute result of this routine
2026  */
2027 static int hdd_tx_timestamp(enum htt_tx_status status,
2028 			    qdf_nbuf_t netbuf, uint64_t target_time)
2029 {
2030 	struct sock *sk = netbuf->sk;
2031 
2032 	if (!sk)
2033 		return -EINVAL;
2034 
2035 	if ((skb_shinfo(netbuf)->tx_flags & SKBTX_HW_TSTAMP) &&
2036 	    !(skb_shinfo(netbuf)->tx_flags & SKBTX_IN_PROGRESS)) {
2037 		struct sock_exterr_skb *serr;
2038 		qdf_nbuf_t new_netbuf;
2039 		int err;
2040 
2041 		if (hdd_netbuf_timestamp(netbuf, target_time) !=
2042 		    HDD_TSF_OP_SUCC)
2043 			return -EINVAL;
2044 
2045 		new_netbuf = qdf_nbuf_clone(netbuf);
2046 		if (!new_netbuf)
2047 			return -ENOMEM;
2048 
2049 		serr = SKB_EXT_ERR(new_netbuf);
2050 		memset(serr, 0, sizeof(*serr));
2051 
2052 		switch (status) {
2053 		case htt_tx_status_ok:
2054 			serr->ee.ee_errno = ENOMSG;
2055 			break;
2056 		case htt_tx_status_discard:
2057 			serr->ee.ee_errno = ENOBUFS;
2058 			break;
2059 		case htt_tx_status_no_ack:
2060 			serr->ee.ee_errno = EREMOTEIO;
2061 			break;
2062 		default:
2063 			serr->ee.ee_errno = ENOMSG;
2064 			break;
2065 		}
2066 
2067 		hdd_debug("packet status %d, sock ee_errno %d",
2068 			  status, serr->ee.ee_errno);
2069 
2070 		serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
2071 
2072 		err = sock_queue_err_skb(sk, new_netbuf);
2073 		if (err) {
2074 			qdf_nbuf_free(new_netbuf);
2075 			return err;
2076 		}
2077 
2078 		return 0;
2079 	}
2080 	return -EINVAL;
2081 }
2082 
2083 int hdd_rx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time)
2084 {
2085 	if (hdd_netbuf_timestamp(netbuf, target_time) ==
2086 		HDD_TSF_OP_SUCC)
2087 		return 0;
2088 
2089 	/* reset tstamp when failed */
2090 	netbuf->tstamp = ktime_set(0, 0);
2091 	return -EINVAL;
2092 }
2093 
2094 static inline void wlan_hdd_tsf_plus_sock_ts_init(struct hdd_context *hdd_ctx)
2095 {
2096 	if (hdd_tsf_is_tx_set(hdd_ctx))
2097 		ol_register_timestamp_callback(hdd_tx_timestamp);
2098 }
2099 
2100 static inline void wlan_hdd_tsf_plus_sock_ts_deinit(struct hdd_context *hdd_ctx)
2101 {
2102 	if (hdd_tsf_is_tx_set(hdd_ctx))
2103 		ol_deregister_timestamp_callback();
2104 }
2105 #else
2106 static inline void wlan_hdd_tsf_plus_sock_ts_init(struct hdd_context *hdd_ctx)
2107 {
2108 }
2109 
2110 static inline void wlan_hdd_tsf_plus_sock_ts_deinit(struct hdd_context *hdd_ctx)
2111 {
2112 }
2113 #endif /* WLAN_FEATURE_TSF_PLUS_SOCK_TS */
2114 
2115 #if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ)
2116 static inline
2117 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2118 {
2119 
2120 	wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx);
2121 	return HDD_TSF_OP_SUCC;
2122 }
2123 
2124 static inline
2125 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2126 {
2127 	QDF_STATUS status;
2128 	QDF_TIMER_STATE capture_req_timer_status;
2129 	qdf_mc_timer_t *cap_timer;
2130 	struct hdd_adapter *adapter, *adapternode_ptr, *next_ptr;
2131 
2132 	wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx);
2133 
2134 	status = hdd_get_front_adapter(hdd_ctx, &adapternode_ptr);
2135 
2136 	while (adapternode_ptr && QDF_STATUS_SUCCESS == status) {
2137 		adapter = adapternode_ptr;
2138 		status =
2139 		    hdd_get_next_adapter(hdd_ctx, adapternode_ptr, &next_ptr);
2140 		adapternode_ptr = next_ptr;
2141 		if (adapter->host_capture_req_timer.state == 0)
2142 			continue;
2143 		cap_timer = &adapter->host_capture_req_timer;
2144 		capture_req_timer_status =
2145 			qdf_mc_timer_get_current_state(cap_timer);
2146 
2147 		if (capture_req_timer_status != QDF_TIMER_STATE_UNUSED) {
2148 			qdf_mc_timer_stop(cap_timer);
2149 			status =
2150 				qdf_mc_timer_destroy(cap_timer);
2151 			if (status != QDF_STATUS_SUCCESS)
2152 				hdd_err("remove timer failed: %d", status);
2153 		}
2154 	}
2155 
2156 	return HDD_TSF_OP_SUCC;
2157 }
2158 
2159 #elif defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
2160 static
2161 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2162 {
2163 	int ret;
2164 	QDF_STATUS status;
2165 	uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID;
2166 
2167 	status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc,
2168 						      &tsf_sync_gpio_pin);
2169 	if (QDF_IS_STATUS_ERROR(status)) {
2170 		hdd_err("tsf gpio irq host pin error");
2171 		goto fail;
2172 	}
2173 
2174 	if (tsf_sync_gpio_pin == TSF_GPIO_PIN_INVALID) {
2175 		hdd_err("gpio host pin is invalid");
2176 		goto fail;
2177 	}
2178 
2179 	ret = gpio_request(tsf_sync_gpio_pin, "wlan_tsf");
2180 	if (ret) {
2181 		hdd_err("gpio host pin is invalid");
2182 		goto fail;
2183 	}
2184 
2185 	ret = gpio_direction_output(tsf_sync_gpio_pin, OUTPUT_LOW);
2186 	if (ret) {
2187 		hdd_err("gpio host pin is invalid");
2188 		goto fail_free_gpio;
2189 	}
2190 
2191 	wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx);
2192 
2193 	return HDD_TSF_OP_SUCC;
2194 
2195 fail_free_gpio:
2196 	gpio_free(tsf_sync_gpio_pin);
2197 fail:
2198 	return HDD_TSF_OP_FAIL;
2199 }
2200 
2201 static
2202 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2203 {
2204 	QDF_STATUS status;
2205 	uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID;
2206 
2207 	status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc,
2208 						      &tsf_sync_gpio_pin);
2209 	if (QDF_IS_STATUS_ERROR(status))
2210 		return QDF_STATUS_E_INVAL;
2211 
2212 	if (tsf_sync_gpio_pin == TSF_GPIO_PIN_INVALID)
2213 		return QDF_STATUS_E_INVAL;
2214 
2215 	wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx);
2216 
2217 	gpio_free(tsf_sync_gpio_pin);
2218 	return HDD_TSF_OP_SUCC;
2219 }
2220 
2221 #elif defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ)
2222 static
2223 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2224 {
2225 	int ret;
2226 	QDF_STATUS status;
2227 	uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID;
2228 
2229 	status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc,
2230 						     &tsf_irq_gpio_pin);
2231 	if (QDF_IS_STATUS_ERROR(status)) {
2232 		hdd_err("tsf gpio irq host pin error");
2233 		goto fail;
2234 	}
2235 
2236 	if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID) {
2237 		hdd_err("gpio host pin is invalid");
2238 		goto fail;
2239 	}
2240 
2241 	ret = gpio_request(tsf_irq_gpio_pin, "wlan_tsf");
2242 	if (ret) {
2243 		hdd_err("gpio host pin is invalid");
2244 		goto fail;
2245 	}
2246 
2247 	ret = gpio_direction_input(tsf_irq_gpio_pin);
2248 	if (ret) {
2249 		hdd_err("gpio host pin is invalid");
2250 		goto fail_free_gpio;
2251 	}
2252 
2253 	tsf_gpio_irq_num = gpio_to_irq(tsf_irq_gpio_pin);
2254 	if (tsf_gpio_irq_num < 0) {
2255 		hdd_err("fail to get irq: %d", tsf_gpio_irq_num);
2256 		goto fail_free_gpio;
2257 	}
2258 
2259 	ret = request_irq(tsf_gpio_irq_num, hdd_tsf_captured_irq_handler,
2260 			  IRQF_SHARED | IRQF_TRIGGER_RISING, "wlan_tsf",
2261 			  hdd_ctx);
2262 
2263 	if (ret) {
2264 		hdd_err("Failed to register irq handler: %d", ret);
2265 		goto fail_free_gpio;
2266 	}
2267 
2268 	wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx);
2269 
2270 	return HDD_TSF_OP_SUCC;
2271 
2272 fail_free_gpio:
2273 	gpio_free(tsf_irq_gpio_pin);
2274 fail:
2275 	tsf_gpio_irq_num = -1;
2276 	return HDD_TSF_OP_FAIL;
2277 }
2278 
2279 static
2280 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2281 {
2282 	QDF_STATUS status;
2283 	uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID;
2284 
2285 	status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc,
2286 						     &tsf_irq_gpio_pin);
2287 	if (QDF_IS_STATUS_ERROR(status))
2288 		return QDF_STATUS_E_INVAL;
2289 
2290 	if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID)
2291 		return QDF_STATUS_E_INVAL;
2292 
2293 	wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx);
2294 
2295 	if (tsf_gpio_irq_num >= 0) {
2296 		free_irq(tsf_gpio_irq_num, hdd_ctx);
2297 		tsf_gpio_irq_num = -1;
2298 		gpio_free(tsf_irq_gpio_pin);
2299 	}
2300 
2301 	return HDD_TSF_OP_SUCC;
2302 }
2303 
2304 #elif defined(WLAN_FEATURE_TSF_TIMER_SYNC)
2305 static inline
2306 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2307 {
2308 	return HDD_TSF_OP_SUCC;
2309 }
2310 
2311 static inline
2312 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2313 {
2314 	QDF_STATUS status;
2315 	QDF_TIMER_STATE capture_req_timer_status;
2316 	qdf_mc_timer_t *cap_timer;
2317 	struct hdd_adapter *adapter, *adapternode_ptr, *next_ptr;
2318 
2319 	status = hdd_get_front_adapter(hdd_ctx, &adapternode_ptr);
2320 
2321 	while (adapternode_ptr && QDF_STATUS_SUCCESS == status) {
2322 		adapter = adapternode_ptr;
2323 		status =
2324 		    hdd_get_next_adapter(hdd_ctx, adapternode_ptr, &next_ptr);
2325 		adapternode_ptr = next_ptr;
2326 		if (adapter->host_capture_req_timer.state == 0)
2327 			continue;
2328 		cap_timer = &adapter->host_capture_req_timer;
2329 		capture_req_timer_status =
2330 			qdf_mc_timer_get_current_state(cap_timer);
2331 
2332 		if (capture_req_timer_status != QDF_TIMER_STATE_UNUSED) {
2333 			qdf_mc_timer_stop(cap_timer);
2334 			status =
2335 				qdf_mc_timer_destroy(cap_timer);
2336 			if (status != QDF_STATUS_SUCCESS)
2337 				hdd_err_rl("remove timer failed: %d", status);
2338 		}
2339 	}
2340 
2341 	return HDD_TSF_OP_SUCC;
2342 }
2343 #else
2344 static inline
2345 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2346 {
2347 	int ret;
2348 
2349 	ret = cnss_common_register_tsf_captured_handler(
2350 			hdd_ctx->parent_dev,
2351 			hdd_tsf_captured_irq_handler,
2352 			(void *)hdd_ctx);
2353 	if (ret != 0) {
2354 		hdd_err("Failed to register irq handler: %d", ret);
2355 		return HDD_TSF_OP_FAIL;
2356 	}
2357 
2358 	wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx);
2359 	return HDD_TSF_OP_SUCC;
2360 }
2361 
2362 static inline
2363 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2364 {
2365 	int ret;
2366 
2367 	wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx);
2368 
2369 	ret = cnss_common_unregister_tsf_captured_handler(
2370 				hdd_ctx->parent_dev,
2371 				(void *)hdd_ctx);
2372 	if (ret != 0) {
2373 		hdd_err("Failed to unregister irq handler, ret:%d",
2374 			ret);
2375 		ret = HDD_TSF_OP_FAIL;
2376 	}
2377 
2378 	return HDD_TSF_OP_SUCC;
2379 }
2380 #endif
2381 #else
2382 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
2383 {
2384 }
2385 
2386 static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter,
2387 						 struct hdd_tsf_op_response
2388 								*tsf_op_resp)
2389 {
2390 	return hdd_indicate_tsf_internal(adapter, tsf_op_resp);
2391 }
2392 
2393 static inline int __hdd_capture_tsf(struct hdd_adapter *adapter,
2394 				    uint32_t *buf, int len)
2395 {
2396 	return (hdd_capture_tsf_internal(adapter, buf, len) ==
2397 		HDD_TSF_OP_SUCC) ? 0 : -EINVAL;
2398 }
2399 
2400 static inline
2401 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2402 {
2403 	return HDD_TSF_OP_SUCC;
2404 }
2405 
2406 static inline
2407 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2408 {
2409 	return HDD_TSF_OP_SUCC;
2410 }
2411 
2412 static inline int hdd_handle_tsf_dynamic_start(struct hdd_adapter *adapter,
2413 					       struct nlattr *attr)
2414 {
2415 	return -ENOTSUPP;
2416 }
2417 
2418 static inline int hdd_handle_tsf_dynamic_stop(struct hdd_adapter *adapter)
2419 {
2420 	return -ENOTSUPP;
2421 }
2422 #endif /* WLAN_FEATURE_TSF_PLUS */
2423 
2424 int hdd_capture_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len)
2425 {
2426 	return __hdd_capture_tsf(adapter, buf, len);
2427 }
2428 
2429 int hdd_indicate_tsf(struct hdd_adapter *adapter,
2430 		     struct hdd_tsf_op_response *tsf_op_resp)
2431 {
2432 	if (__hdd_indicate_tsf(adapter, tsf_op_resp) == HDD_TSF_OP_FAIL)
2433 		return -EINVAL;
2434 
2435 	switch (tsf_op_resp->status) {
2436 	case TSF_RETURN:
2437 		return 0;
2438 	case TSF_NOT_RETURNED_BY_FW:
2439 		return -EINPROGRESS;
2440 	case TSF_STA_NOT_CONNECTED_NO_TSF:
2441 	case TSF_SAP_NOT_STARTED_NO_TSF:
2442 		return -EPERM;
2443 	default:
2444 		return -EINVAL;
2445 	}
2446 }
2447 
2448 #ifdef WLAN_FEATURE_TSF_PTP
2449 int wlan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
2450 
2451 {
2452 	struct hdd_adapter *adapter = netdev_priv(dev);
2453 	struct osif_vdev_sync *vdev_sync;
2454 	struct hdd_context *hdd_ctx;
2455 	int errno;
2456 
2457 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2458 	errno = wlan_hdd_validate_context(hdd_ctx);
2459 	if (errno)
2460 		return -EINVAL;
2461 
2462 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
2463 	if (errno)
2464 		return -EAGAIN;
2465 
2466 	info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
2467 				 SOF_TIMESTAMPING_RX_HARDWARE |
2468 				 SOF_TIMESTAMPING_RAW_HARDWARE;
2469 	if (hdd_ctx->ptp_clock)
2470 		info->phc_index = ptp_clock_index(hdd_ctx->ptp_clock);
2471 	else
2472 		info->phc_index = -1;
2473 
2474 	osif_vdev_sync_op_stop(vdev_sync);
2475 	return 0;
2476 }
2477 
2478 #if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE)
2479 /**
2480  * wlan_ptp_gettime() - return fw ts info to uplayer
2481  * @ptp: pointer to ptp_clock_info.
2482  * @ts: pointer to timespec.
2483  *
2484  * Return: Describe the execute result of this routine
2485  */
2486 static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
2487 {
2488 	uint64_t host_time, target_time = 0;
2489 	struct hdd_context *hdd_ctx;
2490 	struct hdd_adapter *adapter;
2491 	uint32_t tsf_reg_read_enabled;
2492 	struct osif_psoc_sync *psoc_sync;
2493 	int errno, status = 0;
2494 
2495 	hdd_ctx = qdf_container_of(ptp, struct hdd_context, ptp_cinfo);
2496 	errno = wlan_hdd_validate_context(hdd_ctx);
2497 	if (errno)
2498 		return -EINVAL;
2499 
2500 	errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync);
2501 	if (errno)
2502 		return -EAGAIN;
2503 
2504 	adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE);
2505 	if (!adapter) {
2506 		adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE);
2507 		if (!adapter) {
2508 			adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
2509 			if (!adapter)
2510 				adapter = hdd_get_adapter(hdd_ctx,
2511 							  QDF_STA_MODE);
2512 				if (!adapter) {
2513 					status = -EOPNOTSUPP;
2514 					goto end;
2515 				}
2516 		}
2517 	}
2518 
2519 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
2520 	if (hdd_get_targettime_from_hosttime(adapter, host_time,
2521 					     &target_time)) {
2522 		hdd_err("get invalid target timestamp");
2523 		status = -EINVAL;
2524 		goto end;
2525 	}
2526 	*ts = ns_to_timespec(target_time * NSEC_PER_USEC);
2527 
2528 end:
2529 	osif_psoc_sync_op_stop(psoc_sync);
2530 	return status;
2531 }
2532 
2533 /**
2534  * wlan_hdd_phc_init() - phc init
2535  * @hdd_ctx: pointer to the hdd_context.
2536  *
2537  * Return: NULL
2538  */
2539 static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
2540 {
2541 	hdd_ctx->ptp_cinfo.gettime = wlan_ptp_gettime;
2542 
2543 	hdd_ctx->ptp_clock = ptp_clock_register(&hdd_ctx->ptp_cinfo,
2544 						hdd_ctx->parent_dev);
2545 }
2546 
2547 /**
2548  * wlan_hdd_phc_deinit() - phc deinit
2549  * @hdd_ctx: pointer to the hdd_context.
2550  *
2551  * Return: NULL
2552  */
2553 static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
2554 {
2555 	hdd_ctx->ptp_cinfo.gettime = NULL;
2556 
2557 	if (hdd_ctx->ptp_clock) {
2558 		ptp_clock_unregister(hdd_ctx->ptp_clock);
2559 		hdd_ctx->ptp_clock = NULL;
2560 	}
2561 }
2562 
2563 #else
2564 static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
2565 {
2566 	uint64_t host_time, target_time = 0;
2567 	struct hdd_context *hdd_ctx;
2568 	struct hdd_adapter *adapter;
2569 	struct osif_psoc_sync *psoc_sync;
2570 	int errno, status = 0;
2571 
2572 	hdd_ctx = qdf_container_of(ptp, struct hdd_context, ptp_cinfo);
2573 	errno = wlan_hdd_validate_context(hdd_ctx);
2574 	if (errno)
2575 		return -EINVAL;
2576 
2577 	errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync);
2578 	if (errno)
2579 		return -EAGAIN;
2580 
2581 	adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE);
2582 	if (!adapter) {
2583 		adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE);
2584 		if (!adapter) {
2585 			adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
2586 			if (!adapter)
2587 				adapter = hdd_get_adapter(hdd_ctx,
2588 							  QDF_STA_MODE);
2589 				if (!adapter) {
2590 					status = -EOPNOTSUPP;
2591 					goto end;
2592 				}
2593 		}
2594 	}
2595 
2596 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
2597 	if (hdd_get_targettime_from_hosttime(adapter, host_time,
2598 					     &target_time)) {
2599 		hdd_err("get invalid target timestamp");
2600 		status = -EINVAL;
2601 		goto end;
2602 	}
2603 	*ts = ns_to_timespec64(target_time * NSEC_PER_USEC);
2604 
2605 end:
2606 	osif_psoc_sync_op_stop(psoc_sync);
2607 	return status;
2608 }
2609 
2610 static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
2611 {
2612 	hdd_ctx->ptp_cinfo.gettime64 = wlan_ptp_gettime;
2613 	hdd_ctx->ptp_clock = ptp_clock_register(&hdd_ctx->ptp_cinfo,
2614 						hdd_ctx->parent_dev);
2615 }
2616 
2617 static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
2618 {
2619 	hdd_ctx->ptp_cinfo.gettime64 = NULL;
2620 
2621 	if (hdd_ctx->ptp_clock) {
2622 		ptp_clock_unregister(hdd_ctx->ptp_clock);
2623 		hdd_ctx->ptp_clock = NULL;
2624 	}
2625 }
2626 
2627 #endif
2628 #else
2629 
2630 static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
2631 {
2632 }
2633 
2634 static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
2635 {
2636 }
2637 #endif /* WLAN_FEATURE_TSF_PTP */
2638 
2639 #ifdef WLAN_FEATURE_TSF_UPLINK_DELAY
2640 static int hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena)
2641 {
2642 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2643 	int ret;
2644 
2645 	if (QDF_IS_STATUS_ERROR(cdp_set_tsf_ul_delay_report(soc,
2646 							    adapter->vdev_id,
2647 							    ena))) {
2648 		hdd_err_rl("Set tsf report uplink delay failed");
2649 		return -EPERM;
2650 	}
2651 
2652 	ret = wma_cli_set_command((int)adapter->vdev_id,
2653 				  ena ? (int)GEN_PARAM_TSF_AUTO_REPORT_ENABLE :
2654 				  (int)GEN_PARAM_TSF_AUTO_REPORT_DISABLE,
2655 				  ena, GEN_CMD);
2656 	if (ret) {
2657 		hdd_err_rl("tsf auto report %d failed", ena);
2658 		return -EINPROGRESS;
2659 	}
2660 
2661 	qdf_atomic_set(&adapter->tsf_auto_report, ena);
2662 
2663 	return 0;
2664 }
2665 
2666 /**
2667  * hdd_handle_tsf_auto_report(): Handle TSF auto report enable or disable
2668  * @adapter: pointer of struct hdd_adapter
2669  * @tsf_cmd: TSF command from user space
2670  *
2671  * Return: 0 for success, -EINVAL to continue to handle other TSF commands and
2672  *	   else errors
2673  */
2674 static int hdd_handle_tsf_auto_report(struct hdd_adapter *adapter,
2675 				      uint32_t tsf_cmd)
2676 {
2677 	bool ena;
2678 
2679 	if (tsf_cmd != QCA_TSF_AUTO_REPORT_ENABLE &&
2680 	    tsf_cmd != QCA_TSF_AUTO_REPORT_DISABLE) {
2681 		hdd_debug_rl("tsf_cmd %d not for uplink delay", tsf_cmd);
2682 		return -EINVAL;
2683 	}
2684 
2685 	/* uplink delay feature is only required for STA mode */
2686 	if (adapter->device_mode != QDF_STA_MODE) {
2687 		hdd_debug_rl("tsf_cmd %d not allowed for device mode %d",
2688 			     tsf_cmd, adapter->device_mode);
2689 		return -EPERM;
2690 	}
2691 
2692 	ena = (tsf_cmd == QCA_TSF_AUTO_REPORT_ENABLE) ? true : false;
2693 
2694 	return hdd_set_tsf_auto_report(adapter, ena);
2695 }
2696 
2697 static QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter,
2698 				    struct stsf *ptsf)
2699 {
2700 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
2701 	uint32_t delta_tsf;
2702 
2703 	/* If TSF report is for uplink delay, mac_id_valid will be set to
2704 	 * 1 by target. If not, the report is not for uplink delay feature
2705 	 * and return failure here so that legacy BSS TSF logic can be
2706 	 * continued.
2707 	 */
2708 	if (!ptsf->mac_id_valid) {
2709 		hdd_debug_rl("TSF report not for uplink delay");
2710 		return QDF_STATUS_E_FAILURE;
2711 	}
2712 
2713 	/* For uplink delay feature, TSF auto report needs to be enabled
2714 	 * first. Otherwise TSF event will not be posted by target.
2715 	 */
2716 	if (!qdf_atomic_read(&adapter->tsf_auto_report)) {
2717 		hdd_debug_rl("adapter %u tsf_auto_report disabled",
2718 			     adapter->vdev_id);
2719 		goto exit_with_success;
2720 	}
2721 
2722 	delta_tsf = ptsf->tsf_low - ptsf->soc_timer_low;
2723 	hdd_debug("vdev %u tsf_low %u qtimer_low %u delta_tsf %u",
2724 		  ptsf->vdev_id, ptsf->tsf_low, ptsf->soc_timer_low, delta_tsf);
2725 
2726 	/* Pass delta_tsf to DP layer to report uplink delay
2727 	 * on a per vdev basis
2728 	 */
2729 	cdp_set_delta_tsf(soc, adapter->vdev_id, delta_tsf);
2730 
2731 exit_with_success:
2732 	return QDF_STATUS_SUCCESS;
2733 }
2734 #else /* !WLAN_FEATURE_TSF_UPLINK_DELAY */
2735 static inline int hdd_handle_tsf_auto_report(struct hdd_adapter *adapter,
2736 					     uint32_t tsf_cmd)
2737 {
2738 	return -EINVAL;
2739 }
2740 
2741 static inline QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter,
2742 					   struct stsf *ptsf)
2743 {
2744 	return QDF_STATUS_E_FAILURE;
2745 }
2746 #endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */
2747 
2748 /**
2749  * hdd_get_tsf_cb() - handle tsf callback
2750  * @pcb_cxt: pointer to the hdd_contex
2751  * @ptsf: pointer to struct stsf
2752  *
2753  * This function handle the event that reported by firmware at first.
2754  * The event contains the vdev_id, current tsf value of this vdev,
2755  * tsf value is 64bits, discripted in two variable tsf_low and tsf_high.
2756  * These two values each is uint32.
2757  *
2758  * Return: 0 for success or non-zero negative failure code
2759  */
2760 int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf)
2761 {
2762 	struct hdd_context *hddctx;
2763 	struct hdd_adapter *adapter;
2764 	int ret;
2765 	uint64_t tsf_sync_soc_time;
2766 	QDF_STATUS status;
2767 	QDF_TIMER_STATE capture_req_timer_status;
2768 	qdf_mc_timer_t *capture_timer;
2769 
2770 	if (!pcb_cxt || !ptsf) {
2771 		hdd_err("HDD context is not valid");
2772 			return -EINVAL;
2773 	}
2774 
2775 	hddctx = (struct hdd_context *)pcb_cxt;
2776 	ret = wlan_hdd_validate_context(hddctx);
2777 	if (0 != ret)
2778 		return -EINVAL;
2779 
2780 	adapter = hdd_get_adapter_by_vdev(hddctx, ptsf->vdev_id);
2781 
2782 	if (!adapter) {
2783 		hdd_err("failed to find adapter");
2784 		return -EINVAL;
2785 	}
2786 
2787 	/* Intercept tsf report and check if it is for uplink delay.
2788 	 * If yes, return in advance and skip the legacy BSS TSF
2789 	 * report. Otherwise continue on to the legacy BSS TSF
2790 	 * report logic.
2791 	 */
2792 	if (QDF_IS_STATUS_SUCCESS(hdd_set_delta_tsf(adapter, ptsf)))
2793 		return 0;
2794 
2795 	if (!hdd_tsf_is_initialized(adapter)) {
2796 		hdd_err("tsf is not init, ignore tsf event");
2797 		return -EINVAL;
2798 	}
2799 
2800 	hdd_info("tsf cb handle event, device_mode is %d",
2801 		adapter->device_mode);
2802 
2803 	capture_timer = &adapter->host_capture_req_timer;
2804 	capture_req_timer_status =
2805 		qdf_mc_timer_get_current_state(capture_timer);
2806 	if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) {
2807 		hdd_warn("invalid timer status");
2808 		return -EINVAL;
2809 	}
2810 
2811 	qdf_mc_timer_stop(capture_timer);
2812 	status = qdf_mc_timer_destroy(capture_timer);
2813 	if (status != QDF_STATUS_SUCCESS)
2814 		hdd_warn("destroy cap req timer fail, ret: %d", status);
2815 
2816 	adapter->cur_target_time = ((uint64_t)ptsf->tsf_high << 32 |
2817 			 ptsf->tsf_low);
2818 
2819 	adapter->cur_target_global_tsf_time =
2820 		((uint64_t)ptsf->global_tsf_high << 32 |
2821 			 ptsf->global_tsf_low);
2822 	tsf_sync_soc_time = ((uint64_t)ptsf->soc_timer_high << 32 |
2823 			ptsf->soc_timer_low);
2824 	adapter->cur_tsf_sync_soc_time =
2825 		hdd_convert_qtime_to_us(tsf_sync_soc_time) * NSEC_PER_USEC;
2826 
2827 	wlan_hdd_tsf_reg_update_details(adapter, ptsf);
2828 
2829 	qdf_event_set(&tsf_sync_get_completion_evt);
2830 	hdd_update_tsf(adapter, adapter->cur_target_time);
2831 	hdd_info("Vdev=%u, tsf_low=%u, tsf_high=%u ptsf->soc_timer_low=%u ptsf->soc_timer_high=%u",
2832 		 ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high,
2833 		 ptsf->soc_timer_low, ptsf->soc_timer_high);
2834 	return 0;
2835 }
2836 
2837 const struct nla_policy tsf_policy[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1] = {
2838 	[QCA_WLAN_VENDOR_ATTR_TSF_CMD] = {.type = NLA_U32},
2839 	[QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL] = {.type = NLA_U32},
2840 };
2841 
2842 /**
2843  * __wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations
2844  * @wiphy: Pointer to wireless phy
2845  * @wdev: Pointer to wireless device
2846  * @data: Pointer to data
2847  * @data_len: Data length
2848  *
2849  * Handle TSF SET / GET operation from userspace
2850  *
2851  * Return: 0 on success, negative errno on failure
2852  */
2853 static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
2854 					struct wireless_dev *wdev,
2855 					const void *data,
2856 					int data_len)
2857 {
2858 	struct net_device *dev = wdev->netdev;
2859 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2860 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
2861 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1];
2862 	struct hdd_tsf_op_response tsf_op_resp;
2863 	struct nlattr *attr;
2864 	enum hdd_tsf_get_state value;
2865 	int status;
2866 	QDF_STATUS ret;
2867 	struct sk_buff *reply_skb;
2868 	uint32_t tsf_cmd;
2869 
2870 	hdd_enter_dev(wdev->netdev);
2871 
2872 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
2873 		hdd_err("Command not allowed in FTM mode");
2874 		return -EPERM;
2875 	}
2876 
2877 	status = wlan_hdd_validate_context(hdd_ctx);
2878 	if (0 != status)
2879 		return -EINVAL;
2880 
2881 	if (wlan_cfg80211_nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TSF_MAX,
2882 				    data, data_len, tsf_policy)) {
2883 		hdd_err("Invalid TSF cmd");
2884 		return -EINVAL;
2885 	}
2886 
2887 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]) {
2888 		hdd_err("Invalid TSF cmd");
2889 		return -EINVAL;
2890 	}
2891 	tsf_cmd = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]);
2892 
2893 	/* Intercept tsf_cmd for TSF auto report enable or disable subcmds.
2894 	 * If status is -EINVAL, it means tsf_cmd is not for auto report and
2895 	 * need to continue to handle other tsf cmds.
2896 	 */
2897 	status = hdd_handle_tsf_auto_report(adapter, tsf_cmd);
2898 	if (status != -EINVAL)
2899 		goto end;
2900 	ret = qdf_event_reset(&tsf_sync_get_completion_evt);
2901 	if (QDF_IS_STATUS_ERROR(ret))
2902 		hdd_warn("failed to reset tsf_sync_get_completion_evt");
2903 
2904 	if (tsf_cmd == QCA_TSF_CAPTURE || tsf_cmd == QCA_TSF_SYNC_GET) {
2905 		hdd_capture_tsf(adapter, &value, 1);
2906 		switch (value) {
2907 		case TSF_RETURN:
2908 			status = 0;
2909 			break;
2910 		case TSF_CURRENT_IN_CAP_STATE:
2911 			status = -EALREADY;
2912 			break;
2913 		case TSF_STA_NOT_CONNECTED_NO_TSF:
2914 		case TSF_SAP_NOT_STARTED_NO_TSF:
2915 			status = -EPERM;
2916 			break;
2917 		default:
2918 		case TSF_CAPTURE_FAIL:
2919 			status = -EINVAL;
2920 			break;
2921 		}
2922 	} else if (tsf_cmd == QCA_TSF_SYNC_START) {
2923 		attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL];
2924 		status = hdd_handle_tsf_dynamic_start(adapter, attr);
2925 	} else if (tsf_cmd == QCA_TSF_SYNC_STOP) {
2926 		status = hdd_handle_tsf_dynamic_stop(adapter);
2927 	}
2928 
2929 	if (status < 0)
2930 		goto end;
2931 
2932 	if (tsf_cmd == QCA_TSF_SYNC_GET) {
2933 		ret = qdf_wait_single_event(&tsf_sync_get_completion_evt,
2934 					    WLAN_TSF_SYNC_GET_TIMEOUT);
2935 		if (QDF_IS_STATUS_ERROR(ret)) {
2936 			status = -ETIMEDOUT;
2937 			goto end;
2938 		}
2939 	}
2940 
2941 	if (tsf_cmd == QCA_TSF_GET || tsf_cmd == QCA_TSF_SYNC_GET) {
2942 		status = hdd_indicate_tsf(adapter, &tsf_op_resp);
2943 		if (status != 0)
2944 			goto end;
2945 
2946 		reply_skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
2947 					sizeof(uint64_t) * 2 + NLMSG_HDRLEN,
2948 					QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX,
2949 					GFP_KERNEL);
2950 		if (!reply_skb) {
2951 			hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
2952 			status = -ENOMEM;
2953 			goto end;
2954 		}
2955 		if (hdd_wlan_nla_put_u64(reply_skb,
2956 				QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE,
2957 				tsf_op_resp.time) ||
2958 		    hdd_wlan_nla_put_u64(reply_skb,
2959 				QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE,
2960 				tsf_op_resp.soc_time)) {
2961 			hdd_err("nla put fail");
2962 			kfree_skb(reply_skb);
2963 			status = -EINVAL;
2964 			goto end;
2965 		}
2966 		status = cfg80211_vendor_cmd_reply(reply_skb);
2967 	}
2968 
2969 end:
2970 	hdd_info("TSF operation %d status: %d", tsf_cmd, status);
2971 	return status;
2972 }
2973 
2974 int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
2975 					struct wireless_dev *wdev,
2976 					const void *data,
2977 					int data_len)
2978 {
2979 	int errno;
2980 	struct osif_vdev_sync *vdev_sync;
2981 
2982 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
2983 	if (errno)
2984 		return errno;
2985 
2986 	errno = __wlan_hdd_cfg80211_handle_tsf_cmd(wiphy, wdev, data, data_len);
2987 
2988 	osif_vdev_sync_op_stop(vdev_sync);
2989 
2990 	return errno;
2991 }
2992 
2993 /**
2994  * wlan_hdd_tsf_init() - set callback to handle tsf value.
2995  * @hdd_ctx: pointer to the struct hdd_context
2996  *
2997  * This function set the callback to sme module, the callback will be
2998  * called when a tsf event is reported by firmware
2999  *
3000  * Return: none
3001  */
3002 void wlan_hdd_tsf_init(struct hdd_context *hdd_ctx)
3003 {
3004 	QDF_STATUS status;
3005 
3006 	if (!hdd_ctx)
3007 		return;
3008 
3009 	if (qdf_atomic_inc_return(&hdd_ctx->tsf_ready_flag) > 1)
3010 		return;
3011 
3012 	qdf_atomic_init(&hdd_ctx->cap_tsf_flag);
3013 
3014 	status = hdd_tsf_set_gpio(hdd_ctx);
3015 
3016 	if (QDF_STATUS_SUCCESS != status) {
3017 		hdd_debug("set tsf GPIO failed, status: %d", status);
3018 		goto fail;
3019 	}
3020 
3021 	if (wlan_hdd_tsf_plus_init(hdd_ctx) != HDD_TSF_OP_SUCC)
3022 		goto fail;
3023 
3024 	if (hdd_tsf_is_ptp_enabled(hdd_ctx))
3025 		wlan_hdd_phc_init(hdd_ctx);
3026 
3027 	status = qdf_event_create(&tsf_sync_get_completion_evt);
3028 	if (QDF_IS_STATUS_ERROR(status)) {
3029 		hdd_debug("failed to create tsf_sync_get_completion_evt");
3030 		goto fail;
3031 	}
3032 
3033 	return;
3034 
3035 fail:
3036 	qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0);
3037 }
3038 
3039 void wlan_hdd_tsf_deinit(struct hdd_context *hdd_ctx)
3040 {
3041 	QDF_STATUS status;
3042 
3043 	if (!hdd_ctx)
3044 		return;
3045 
3046 	if (!qdf_atomic_read(&hdd_ctx->tsf_ready_flag))
3047 		return;
3048 
3049 	status = qdf_event_destroy(&tsf_sync_get_completion_evt);
3050 	if (QDF_IS_STATUS_ERROR(status))
3051 		hdd_debug("failed to destroy tsf_sync_get_completion_evt");
3052 
3053 	if (hdd_tsf_is_ptp_enabled(hdd_ctx))
3054 		wlan_hdd_phc_deinit(hdd_ctx);
3055 	wlan_hdd_tsf_plus_deinit(hdd_ctx);
3056 	qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0);
3057 	qdf_atomic_set(&hdd_ctx->cap_tsf_flag, 0);
3058 }
3059