xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_tsf.c (revision 5113495b16420b49004c444715d2daae2066e7dc) !
1 /*
2  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 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  * DOC: 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 	defined(WLAN_FEATURE_TSF_ACCURACY)
34 #include <linux/gpio.h>
35 #endif
36 
37 #include "ol_txrx_api.h"
38 #ifdef WLAN_FEATURE_TSF_AUTO_REPORT
39 #include <cdp_txrx_ctrl.h>
40 #endif
41 
42 #ifdef WLAN_FEATURE_TSF_PLUS
43 #if !defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && \
44 	!defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) && \
45 	!defined(WLAN_FEATURE_TSF_TIMER_SYNC)
46 static int tsf_gpio_irq_num = -1;
47 #endif
48 #endif
49 static qdf_event_t tsf_sync_get_completion_evt;
50 #define WLAN_TSF_SYNC_GET_TIMEOUT 2000
51 #define WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS 500
52 #define WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS 100
53 #ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC
54 #define WLAN_HDD_SOFTAP_INTERVAL_TIMES 1
55 #else
56 #define WLAN_HDD_SOFTAP_INTERVAL_TIMES 100
57 #endif
58 #define OUTPUT_HIGH 1
59 #define OUTPUT_LOW 0
60 
61 #ifdef WLAN_FEATURE_TSF_PLUS
62 #if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) || \
63 	defined(WLAN_FEATURE_TSF_TIMER_SYNC)
64 static void hdd_update_timestamp(struct hdd_adapter *adapter);
65 #else
66 static void
67 hdd_update_timestamp(struct hdd_adapter *adapter,
68 		     uint64_t target_time, uint64_t host_time);
69 #endif
70 #endif
71 
72 #ifdef QCA_GET_TSF_VIA_REG
73 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf);
74 
75 /**
76  * struct hdd_tsf_report - TSF report filled in by DP layer
77  * @vdev_id: vdev id for which TSF values is to be read
78  * @tsf_id: tsf if used to read TSF report
79  * @mac_id: lmac_id for which TSF values are read
80  * @tsf: 64 bit tsf value as read from scratch registers
81  * @tsf_sync_soc_time: host qtimer time when scratch registers are read
82  *
83  * The structure is used by the upper layers to pass vdev_id, tsf_id and mac_id
84  * information to DP layer and get tsf time and host time when TSF was read.
85  */
86 struct hdd_tsf_report {
87 	uint32_t vdev_id;
88 	uint32_t tsf_id;
89 	uint32_t mac_id;
90 	uint64_t tsf;
91 	uint64_t tsf_sync_soc_time;
92 };
93 #endif
94 
95 /**
96  * enum hdd_tsf_op_result - result of tsf operation
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
hdd_set_th_sync_status(struct hdd_adapter * adapter,bool initialized)111 static inline void hdd_set_th_sync_status(struct hdd_adapter *adapter,
112 					  bool initialized)
113 {
114 	qdf_atomic_set(&adapter->tsf.tsf_sync_ready_flag,
115 		       (initialized ? 1 : 0));
116 }
117 
hdd_get_th_sync_status(struct hdd_adapter * adapter)118 static inline bool hdd_get_th_sync_status(struct hdd_adapter *adapter)
119 {
120 	return qdf_atomic_read(&adapter->tsf.tsf_sync_ready_flag) != 0;
121 }
122 
123 #else
hdd_get_th_sync_status(struct hdd_adapter * adapter)124 static inline bool hdd_get_th_sync_status(struct hdd_adapter *adapter)
125 {
126 	return true;
127 }
128 #endif
129 
130 static
hdd_tsf_check_conn_state(struct hdd_adapter * adapter)131 enum hdd_tsf_get_state hdd_tsf_check_conn_state(struct hdd_adapter *adapter)
132 {
133 	enum QDF_OPMODE mode;
134 	enum hdd_tsf_get_state ret = TSF_RETURN;
135 
136 	mode = adapter->device_mode;
137 
138 	if (!test_bit(SOFTAP_BSS_STARTED, &adapter->deflink->link_flags) &&
139 	    (mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE)) {
140 		hdd_err("Soft AP / P2p GO not beaconing");
141 		ret = TSF_SAP_NOT_STARTED_NO_TSF;
142 	} else if (!hdd_cm_is_vdev_associated(adapter->deflink) &&
143 		   (mode == QDF_STA_MODE || mode == QDF_P2P_CLIENT_MODE)) {
144 		hdd_err("failed to cap tsf, not connect with ap");
145 		ret = TSF_STA_NOT_CONNECTED_NO_TSF;
146 	}
147 
148 	return ret;
149 }
150 
hdd_tsf_is_initialized(struct hdd_adapter * adapter)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.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  */
hdd_tsf_reset_gpio(struct hdd_adapter * adapter)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 
hdd_tsf_set_gpio(struct hdd_context * hdd_ctx)203 static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx)
204 {
205 	return QDF_STATUS_SUCCESS;
206 }
207 #else
hdd_tsf_reset_gpio(struct hdd_adapter * adapter)208 static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter)
209 {
210 	int ret;
211 
212 	ret = wma_cli_set_command((int)adapter->deflink->vdev_id,
213 				  (int)GEN_PARAM_RESET_TSF_GPIO,
214 				  adapter->deflink->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  */
hdd_tsf_set_gpio(struct hdd_context * hdd_ctx)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
hdd_tsf_is_ptp_enabled(struct hdd_context * hdd)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 
hdd_tsf_is_tx_set(struct hdd_context * hdd)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 
hdd_tsf_is_rx_set(struct hdd_context * hdd)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 
hdd_tsf_is_raw_set(struct hdd_context * hdd)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 
hdd_tsf_is_dbg_fs_set(struct hdd_context * hdd)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 
hdd_tsf_is_tsf64_tx_set(struct hdd_context * hdd)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 
hdd_tsf_is_time_sync_enabled_cfg(struct hdd_context * hdd_ctx)321 bool hdd_tsf_is_time_sync_enabled_cfg(struct hdd_context *hdd_ctx)
322 {
323 	uint32_t tsf_ptp_options;
324 
325 	if (hdd_ctx && QDF_IS_STATUS_SUCCESS(
326 	    ucfg_fwol_get_tsf_ptp_options(hdd_ctx->psoc, &tsf_ptp_options)))
327 		return tsf_ptp_options & CFG_SET_TSF_PTP_SYNC_PERIOD;
328 	else
329 		return false;
330 }
331 
hdd_is_tsf_sync_enabled(struct hdd_context * hdd)332 static bool hdd_is_tsf_sync_enabled(struct hdd_context *hdd)
333 {
334 	bool is_tsf_sync_enable;
335 
336 	if (hdd && QDF_IS_STATUS_SUCCESS(
337 	    ucfg_fwol_get_tsf_sync_enable(hdd->psoc, &is_tsf_sync_enable)))
338 		return is_tsf_sync_enable;
339 	else
340 		return false;
341 }
342 
hdd_update_dynamic_tsf_sync(struct hdd_adapter * adapter)343 void hdd_update_dynamic_tsf_sync(struct hdd_adapter *adapter)
344 {
345 	adapter->tsf.enable_dynamic_tsf_sync =
346 			hdd_is_tsf_sync_enabled(adapter->hdd_ctx);
347 }
348 #else
349 
hdd_tsf_is_ptp_enabled(struct hdd_context * hdd)350 static bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd)
351 {
352 	return false;
353 }
354 #endif
355 
356 #ifdef WLAN_FEATURE_TSF_PLUS
357 static inline
hdd_get_monotonic_host_time(struct hdd_context * hdd_ctx)358 uint64_t hdd_get_monotonic_host_time(struct hdd_context *hdd_ctx)
359 {
360 	return hdd_tsf_is_raw_set(hdd_ctx) ?
361 		ktime_get_ns() : ktime_get_real_ns();
362 }
363 #endif
364 
365 #if defined(WLAN_FEATURE_TSF_PLUS) && \
366 	defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
367 #define MAX_CONTINUOUS_RETRY_CNT 10
368 static uint32_t
hdd_wlan_retry_tsf_cap(struct hdd_adapter * adapter)369 hdd_wlan_retry_tsf_cap(struct hdd_adapter *adapter)
370 {
371 	struct hdd_context *hddctx;
372 	int count = adapter->tsf.continuous_cap_retry_count;
373 
374 	hddctx = WLAN_HDD_GET_CTX(adapter);
375 	if (count == MAX_CONTINUOUS_RETRY_CNT) {
376 		hdd_debug("Max retry count reached");
377 		return 0;
378 	}
379 	qdf_atomic_set(&hddctx->tsf.cap_tsf_flag, 0);
380 	count++;
381 	adapter->tsf.continuous_cap_retry_count = count;
382 	return (count * WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS);
383 }
384 
385 static void
hdd_wlan_restart_tsf_cap(struct hdd_adapter * adapter)386 hdd_wlan_restart_tsf_cap(struct hdd_adapter *adapter)
387 {
388 	struct hdd_context *hddctx;
389 	int count = adapter->tsf.continuous_cap_retry_count;
390 
391 	hddctx = WLAN_HDD_GET_CTX(adapter);
392 	if (count == MAX_CONTINUOUS_RETRY_CNT) {
393 		hdd_debug("Restart TSF CAP");
394 		qdf_atomic_set(&hddctx->tsf.cap_tsf_flag, 0);
395 		adapter->tsf.continuous_cap_retry_count = 0;
396 		qdf_mc_timer_start(&adapter->tsf.host_target_sync_timer,
397 				   WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS);
398 	}
399 }
400 
401 static void
hdd_update_host_time(struct hdd_adapter * adapter)402 hdd_update_host_time(struct hdd_adapter *adapter)
403 {
404 	struct hdd_context *hdd_ctx;
405 	u64 host_time;
406 	char *name = NULL;
407 
408 	hdd_ctx = adapter->hdd_ctx;
409 
410 	if (!hdd_tsf_is_initialized(adapter)) {
411 		hdd_err("tsf is not init, exit");
412 		return;
413 	}
414 
415 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
416 	hdd_update_timestamp(adapter, 0, host_time);
417 	name = adapter->dev->name;
418 
419 	hdd_debug("iface: %s - host_time: %llu",
420 		  (!name ? "none" : name), host_time);
421 }
422 
423 static
hdd_tsf_ext_gpio_sync_work(void * data)424 void hdd_tsf_ext_gpio_sync_work(void *data)
425 {
426 	QDF_STATUS status;
427 	struct hdd_adapter *adapter;
428 	struct hdd_context *hdd_ctx;
429 	uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID;
430 
431 	adapter = data;
432 	hdd_ctx = adapter->hdd_ctx;
433 	status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc,
434 						      &tsf_sync_gpio_pin);
435 	if (QDF_IS_STATUS_ERROR(status)) {
436 		hdd_err("tsf sync gpio host pin error");
437 		return;
438 	}
439 	gpio_set_value(tsf_sync_gpio_pin, OUTPUT_HIGH);
440 	hdd_update_host_time(adapter);
441 	usleep_range(50, 100);
442 	gpio_set_value(tsf_sync_gpio_pin, OUTPUT_LOW);
443 
444 	status = wma_cli_set_command((int)adapter->deflink->vdev_id,
445 				     (int)GEN_PARAM_CAPTURE_TSF,
446 				     adapter->deflink->vdev_id, GEN_CMD);
447 	if (status != QDF_STATUS_SUCCESS) {
448 		hdd_err("cap tsf fail");
449 		qdf_mc_timer_stop(&adapter->tsf.host_capture_req_timer);
450 	}
451 }
452 
453 static void
hdd_tsf_gpio_sync_work_init(struct hdd_adapter * adapter)454 hdd_tsf_gpio_sync_work_init(struct hdd_adapter *adapter)
455 {
456 	qdf_create_work(0, &adapter->tsf.gpio_tsf_sync_work,
457 			hdd_tsf_ext_gpio_sync_work, adapter);
458 }
459 
460 static void
hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter * adapter)461 hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter *adapter)
462 {
463 	qdf_destroy_work(0, &adapter->tsf.gpio_tsf_sync_work);
464 }
465 
466 static void
hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter * adapter)467 hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter *adapter)
468 {
469 	qdf_cancel_work(&adapter->tsf.gpio_tsf_sync_work);
470 }
471 
472 static void
hdd_tsf_start_ext_gpio_sync(struct hdd_adapter * adapter)473 hdd_tsf_start_ext_gpio_sync(struct hdd_adapter *adapter)
474 {
475 	qdf_sched_work(0, &adapter->tsf.gpio_tsf_sync_work);
476 }
477 
hdd_tsf_cap_sync_send(struct hdd_adapter * adapter)478 static bool hdd_tsf_cap_sync_send(struct hdd_adapter *adapter)
479 {
480 	hdd_tsf_start_ext_gpio_sync(adapter);
481 	return true;
482 }
483 #elif defined(WLAN_FEATURE_TSF_PLUS) && \
484 	!defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
485 static void
hdd_wlan_restart_tsf_cap(struct hdd_adapter * adapter)486 hdd_wlan_restart_tsf_cap(struct hdd_adapter *adapter)
487 {
488 }
489 
490 static void
hdd_tsf_gpio_sync_work_init(struct hdd_adapter * adapter)491 hdd_tsf_gpio_sync_work_init(struct hdd_adapter *adapter)
492 {
493 }
494 
495 static void
hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter * adapter)496 hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter *adapter)
497 {
498 }
499 
500 static void
hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter * adapter)501 hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter *adapter)
502 {
503 }
504 
505 static void
hdd_tsf_start_ext_gpio_sync(struct hdd_adapter * adapter)506 hdd_tsf_start_ext_gpio_sync(struct hdd_adapter *adapter)
507 {
508 }
509 
510 static bool
hdd_tsf_cap_sync_send(struct hdd_adapter * adapter)511 hdd_tsf_cap_sync_send(struct hdd_adapter *adapter)
512 {
513 	hdd_tsf_start_ext_gpio_sync(adapter);
514 	return false;
515 }
516 
517 #else
hdd_tsf_cap_sync_send(struct hdd_adapter * adapter)518 static bool hdd_tsf_cap_sync_send(struct hdd_adapter *adapter)
519 {
520 	return false;
521 }
522 #endif
523 
524 #ifdef WLAN_FEATURE_TSF_TIMER_SYNC
525 /**
526  * hdd_convert_qtime_to_us() - convert qtime to us
527  * @time: QTIMER ticks for adrastea and us for Lithium
528  *
529  * This function converts qtime to us.
530  *
531  * Return: Time in microseconds
532  */
533 static inline uint64_t
hdd_convert_qtime_to_us(uint64_t time)534 hdd_convert_qtime_to_us(uint64_t time)
535 {
536 	return time;
537 }
538 
539 #else
540 static inline uint64_t
hdd_convert_qtime_to_us(uint64_t time)541 hdd_convert_qtime_to_us(uint64_t time)
542 {
543 	return qdf_log_timestamp_to_usecs(time);
544 }
545 #endif
546 
547 /**
548  * hdd_capture_tsf_internal_via_wmi() - convert qtime to us
549  * @adapter: pointer to adapter
550  * @buf: in case of failure update with fail
551  * @len: buffer length
552  *
553  * Return: result of tsf operation
554  */
555 static enum hdd_tsf_op_result
hdd_capture_tsf_internal_via_wmi(struct hdd_adapter * adapter,uint32_t * buf,int len)556 hdd_capture_tsf_internal_via_wmi(struct hdd_adapter *adapter, uint32_t *buf,
557 				 int len)
558 {
559 	int ret;
560 	struct hdd_context *hddctx = adapter->hdd_ctx;
561 
562 	ret = wma_cli_set_command((int)adapter->deflink->vdev_id,
563 				  (int)GEN_PARAM_CAPTURE_TSF,
564 				  adapter->deflink->vdev_id, GEN_CMD);
565 	if (ret != QDF_STATUS_SUCCESS) {
566 		hdd_err("cap tsf fail");
567 		buf[0] = TSF_CAPTURE_FAIL;
568 		hddctx->tsf.cap_tsf_context = NULL;
569 		qdf_atomic_set(&hddctx->tsf.cap_tsf_flag, 0);
570 		qdf_mc_timer_stop(&adapter->tsf.host_capture_req_timer);
571 	}
572 	return HDD_TSF_OP_SUCC;
573 }
574 
575 #ifndef QCA_GET_TSF_VIA_REG
576 static inline
_hdd_capture_tsf_internal(struct hdd_adapter * adapter,uint32_t * buf,int len)577 enum hdd_tsf_op_result _hdd_capture_tsf_internal(struct hdd_adapter *adapter,
578 						 uint32_t *buf, int len)
579 {
580 	return hdd_capture_tsf_internal_via_wmi(adapter, buf, len);
581 }
582 
wlan_hdd_tsf_reg_update_details(struct hdd_adapter * adapter,struct stsf * ptsf)583 static inline void wlan_hdd_tsf_reg_update_details(struct hdd_adapter *adapter,
584 						   struct stsf *ptsf)
585 {
586 }
587 #else
588 
hdd_tsf_reg_is_details_valid(struct hdd_adapter * adapter)589 static inline int hdd_tsf_reg_is_details_valid(struct hdd_adapter *adapter)
590 {
591 	return qdf_atomic_read(&adapter->tsf.tsf_details_valid);
592 }
593 
594 static inline void
wlan_hdd_tsf_reg_update_details(struct hdd_adapter * adapter,struct stsf * ptsf)595 wlan_hdd_tsf_reg_update_details(struct hdd_adapter *adapter, struct stsf *ptsf)
596 {
597 	if (ptsf->tsf_id_valid) {
598 		adapter->tsf.tsf_id = ptsf->tsf_id;
599 		adapter->tsf.tsf_mac_id = ptsf->mac_id;
600 		qdf_atomic_set(&adapter->tsf.tsf_details_valid, 1);
601 	}
602 	hdd_debug("vdev_id %u tsf_id %u tsf_id_valid %u mac_id %u",
603 		  adapter->deflink->vdev_id, ptsf->tsf_id, ptsf->tsf_id_valid,
604 		  ptsf->mac_id);
605 }
606 
607 static inline
wlan_hdd_tsf_reg_get(struct hdd_adapter * adapter,struct hdd_tsf_report * tsf_report)608 QDF_STATUS wlan_hdd_tsf_reg_get(struct hdd_adapter *adapter,
609 				struct hdd_tsf_report *tsf_report)
610 {
611 	ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC);
612 	uint64_t tsf_time = 0;
613 	uint64_t tsf_sync_soc_time = 0;
614 
615 	if (qdf_unlikely(!soc))
616 		return QDF_STATUS_E_INVAL;
617 
618 	cdp_get_tsf_time(soc, tsf_report->tsf_id, tsf_report->mac_id,
619 			 &tsf_time, &tsf_sync_soc_time);
620 
621 	/* fill in the report */
622 	tsf_report->tsf = tsf_time;
623 	tsf_report->tsf_sync_soc_time = tsf_sync_soc_time;
624 	return QDF_STATUS_SUCCESS;
625 }
626 
627 /**
628  * wlan_hdd_tsf_reg_process_report() - Process tsf report
629  * @adapter: pointer to the adapter
630  * @tsf_report: pointer to tsf report
631  *
632  * This function process the tsf report received and update tsf
633  * value received via scratch register read to adapter
634  *
635  * Return: 0 for success or 1 in case of failure
636  */
637 static enum hdd_tsf_op_result
wlan_hdd_tsf_reg_process_report(struct hdd_adapter * adapter,struct hdd_tsf_report * tsf_report)638 wlan_hdd_tsf_reg_process_report(struct hdd_adapter *adapter,
639 				struct hdd_tsf_report *tsf_report)
640 {
641 	struct hdd_vdev_tsf *tsf;
642 	QDF_TIMER_STATE capture_req_timer_status;
643 	qdf_mc_timer_t *capture_timer;
644 
645 	if (!tsf_report->tsf && !tsf_report->tsf_sync_soc_time) {
646 		hdd_err("Invalid TSF report");
647 		return HDD_TSF_OP_FAIL;
648 	}
649 
650 	if (!hdd_tsf_is_initialized(adapter)) {
651 		hdd_err("tsf is not init, ignore tsf event");
652 		return HDD_TSF_OP_FAIL;
653 	}
654 
655 	hdd_debug("device_mode is %d", adapter->device_mode);
656 
657 	tsf = &adapter->tsf;
658 	capture_timer = &tsf->host_capture_req_timer;
659 	capture_req_timer_status =
660 		qdf_mc_timer_get_current_state(capture_timer);
661 	if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) {
662 		hdd_warn("invalid timer status");
663 		return HDD_TSF_OP_FAIL;
664 	}
665 
666 	qdf_mc_timer_stop(capture_timer);
667 	tsf->cur_target_time = tsf_report->tsf;
668 	tsf->cur_tsf_sync_soc_time = tsf_report->tsf_sync_soc_time *
669 						NSEC_PER_USEC;
670 
671 	qdf_event_set(&tsf_sync_get_completion_evt);
672 	hdd_update_tsf(adapter, tsf->cur_target_time);
673 	hdd_debug("vdev id=%u, tsf=%llu", adapter->deflink->vdev_id,
674 		  tsf_report->tsf);
675 	return HDD_TSF_OP_SUCC;
676 }
677 
678 static enum hdd_tsf_op_result
hdd_capture_tsf_internal_via_reg(struct hdd_adapter * adapter,uint32_t * buf,int len)679 hdd_capture_tsf_internal_via_reg(struct hdd_adapter *adapter, uint32_t *buf,
680 				 int len)
681 {
682 	struct hdd_tsf_report tsf_report;
683 
684 	if (!hdd_tsf_reg_is_details_valid(adapter)) {
685 		hdd_warn("TSF reg details are not valid!");
686 		return HDD_TSF_OP_FAIL;
687 	}
688 
689 	qdf_mem_zero(&tsf_report, sizeof(tsf_report));
690 	tsf_report.vdev_id = adapter->deflink->vdev_id;
691 	tsf_report.tsf_id = adapter->tsf.tsf_id;
692 	tsf_report.mac_id = adapter->tsf.tsf_mac_id;
693 
694 	if (wlan_hdd_tsf_reg_get(adapter, &tsf_report)) {
695 		hdd_warn("Unable to get tsf report");
696 		return HDD_TSF_OP_FAIL;
697 	}
698 
699 	return wlan_hdd_tsf_reg_process_report(adapter, &tsf_report);
700 }
701 
702 static inline
_hdd_capture_tsf_internal(struct hdd_adapter * adapter,uint32_t * buf,int len)703 enum hdd_tsf_op_result _hdd_capture_tsf_internal(struct hdd_adapter *adapter,
704 						 uint32_t *buf, int len)
705 {
706 	if (!qdf_atomic_read(&adapter->tsf.tsf_details_valid))
707 		return hdd_capture_tsf_internal_via_wmi(adapter, buf, len);
708 	else
709 		return hdd_capture_tsf_internal_via_reg(adapter, buf, len);
710 }
711 
712 #endif /* QCA_GET_TSF_VIA_REG */
713 
hdd_capture_tsf_internal(struct hdd_adapter * adapter,uint32_t * buf,int len)714 static enum hdd_tsf_op_result hdd_capture_tsf_internal(
715 	struct hdd_adapter *adapter, uint32_t *buf, int len)
716 {
717 	enum hdd_tsf_op_result ret;
718 	struct hdd_context *hddctx;
719 	qdf_mc_timer_t *cap_timer;
720 
721 	if (!adapter || !buf) {
722 		hdd_err("invalid pointer");
723 		return HDD_TSF_OP_FAIL;
724 	}
725 
726 	if (len != 1)
727 		return HDD_TSF_OP_FAIL;
728 
729 	hddctx = WLAN_HDD_GET_CTX(adapter);
730 	if (!hddctx) {
731 		hdd_err("invalid hdd context");
732 		return HDD_TSF_OP_FAIL;
733 	}
734 
735 	if (wlan_hdd_validate_context(hddctx)) {
736 		hdd_err("hdd context validation failed");
737 		return HDD_TSF_OP_FAIL;
738 	}
739 
740 	if (!hdd_tsf_is_initialized(adapter)) {
741 		buf[0] = TSF_NOT_READY;
742 		return HDD_TSF_OP_SUCC;
743 	}
744 
745 	buf[0] = hdd_tsf_check_conn_state(adapter);
746 	if (buf[0] != TSF_RETURN)
747 		return HDD_TSF_OP_SUCC;
748 
749 	if (qdf_atomic_inc_return(&hddctx->tsf.cap_tsf_flag) > 1) {
750 		hdd_err("current in capture state");
751 		buf[0] = TSF_CURRENT_IN_CAP_STATE;
752 		return HDD_TSF_OP_SUCC;
753 	}
754 
755 	/* record adapter for cap_tsf_irq_handler  */
756 	hddctx->tsf.cap_tsf_context = adapter;
757 
758 	hdd_debug("+ioctl issue cap tsf cmd");
759 	cap_timer = &adapter->tsf.host_capture_req_timer;
760 	qdf_mc_timer_start(cap_timer, WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS);
761 
762 	/* Reset TSF value for new capture */
763 	adapter->tsf.cur_target_time = 0;
764 
765 	buf[0] = TSF_RETURN;
766 
767 	if (hdd_tsf_cap_sync_send(adapter))
768 		return HDD_TSF_OP_SUCC;
769 
770 	ret = _hdd_capture_tsf_internal(adapter, buf, len);
771 	hdd_debug("-ioctl return cap tsf cmd");
772 
773 	return ret;
774 }
775 
hdd_indicate_tsf_internal(struct hdd_adapter * adapter,struct hdd_tsf_op_response * tsf_op_resp)776 static enum hdd_tsf_op_result hdd_indicate_tsf_internal(
777 	struct hdd_adapter *adapter, struct hdd_tsf_op_response *tsf_op_resp)
778 {
779 	int ret;
780 	struct hdd_context *hddctx;
781 
782 	if (!adapter || !tsf_op_resp) {
783 		hdd_err("invalid pointer");
784 		return HDD_TSF_OP_FAIL;
785 	}
786 
787 	hddctx = WLAN_HDD_GET_CTX(adapter);
788 	if (!hddctx) {
789 		hdd_err("invalid hdd context");
790 		return HDD_TSF_OP_FAIL;
791 	}
792 
793 	memset(tsf_op_resp, 0, sizeof(*tsf_op_resp));
794 	if (!hdd_tsf_is_initialized(adapter)) {
795 		tsf_op_resp->status = TSF_NOT_READY;
796 		return HDD_TSF_OP_SUCC;
797 	}
798 
799 	tsf_op_resp->status = hdd_tsf_check_conn_state(adapter);
800 	if (tsf_op_resp->status != TSF_RETURN)
801 		return HDD_TSF_OP_SUCC;
802 
803 	if (adapter->tsf.cur_target_time == 0) {
804 		hdd_info("TSF value not received");
805 		tsf_op_resp->status = TSF_NOT_RETURNED_BY_FW;
806 		return HDD_TSF_OP_SUCC;
807 	}
808 
809 	tsf_op_resp->status = TSF_RETURN;
810 	tsf_op_resp->time = adapter->tsf.cur_target_time;
811 	tsf_op_resp->soc_time = adapter->tsf.cur_tsf_sync_soc_time;
812 
813 	if (!qdf_atomic_read(&hddctx->tsf.cap_tsf_flag)) {
814 		hdd_debug("old: status=%u, tsf_time=%llu, tsf_soc_time=%llu",
815 			  tsf_op_resp->status,
816 			  tsf_op_resp->time,
817 			  tsf_op_resp->soc_time);
818 		return HDD_TSF_OP_SUCC;
819 	}
820 
821 	ret = hdd_tsf_reset_gpio(adapter);
822 	if (0 != ret) {
823 		hdd_err("reset tsf gpio fail");
824 		tsf_op_resp->status = TSF_RESET_GPIO_FAIL;
825 		return HDD_TSF_OP_SUCC;
826 	}
827 	hddctx->tsf.cap_tsf_context = NULL;
828 	qdf_atomic_set(&hddctx->tsf.cap_tsf_flag, 0);
829 	hdd_debug("get tsf cmd,status=%u, tsf_time=%llu, tsf_soc_time=%llu",
830 		  tsf_op_resp->status,
831 		  tsf_op_resp->time,
832 		  tsf_op_resp->soc_time);
833 
834 	return HDD_TSF_OP_SUCC;
835 }
836 
837 #ifdef WLAN_FEATURE_TSF_PLUS
838 /* unit for target time: us;  host time: ns */
839 #define HOST_TO_TARGET_TIME_RATIO NSEC_PER_USEC
840 #define MAX_ALLOWED_DEVIATION_NS (100 * NSEC_PER_USEC)
841 #define MAX_CONTINUOUS_ERROR_CNT 3
842 
843 /* to distinguish 32-bit overflow case, this interval should:
844  * equal or less than (1/2 * OVERFLOW_INDICATOR32 us)
845  */
846 #if defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ) || \
847 	defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
848 #define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 2
849 #else
850 #define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 4
851 #endif
852 #define OVERFLOW_INDICATOR32 (((int64_t)0x1) << 32)
853 #define CAP_TSF_TIMER_FIX_SEC 1
854 
855 /**
856  * enum hdd_ts_status - timestamp status
857  * @HDD_TS_STATUS_WAITING:  one of the stamp-pair 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
__hdd_start_tsf_sync(struct hdd_adapter * adapter)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->tsf.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
__hdd_stop_tsf_sync(struct hdd_adapter * adapter)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_debug("Host Target sync has not initialized");
901 		return HDD_TSF_OP_SUCC;
902 	}
903 
904 	ret = qdf_mc_timer_stop(&adapter->tsf.host_target_sync_timer);
905 	if (ret != QDF_STATUS_SUCCESS) {
906 		hdd_err("Failed to stop target timer, ret: %d", ret);
907 		return HDD_TSF_OP_FAIL;
908 	}
909 
910 	ret = qdf_mc_timer_stop(&adapter->tsf.host_capture_req_timer);
911 	if (ret != QDF_STATUS_SUCCESS) {
912 		hdd_err("Failed to stop capture timer, ret: %d", ret);
913 		return HDD_TSF_OP_FAIL;
914 	}
915 
916 	hdd_tsf_stop_ext_gpio_sync(adapter);
917 	hdd_tsf_gpio_sync_work_deinit(adapter);
918 	return HDD_TSF_OP_SUCC;
919 }
920 
hdd_reset_timestamps(struct hdd_adapter * adapter)921 static inline void hdd_reset_timestamps(struct hdd_adapter *adapter)
922 {
923 	struct hdd_vdev_tsf *tsf = &adapter->tsf;
924 
925 	qdf_spin_lock_bh(&tsf->host_target_sync_lock);
926 	tsf->cur_host_time = 0;
927 	tsf->cur_target_time = 0;
928 	tsf->last_host_time = 0;
929 	tsf->last_target_time = 0;
930 	qdf_spin_unlock_bh(&tsf->host_target_sync_lock);
931 }
932 
933 /**
934  * hdd_check_timestamp_status() - return the tstamp status
935  * @last_target_time: the last saved target time
936  * @last_sync_time: the last saved sync time
937  * @cur_target_time: new target time
938  * @cur_sync_time: new sync time
939  * @force_sync: flag to force new timestamp-pair as valid
940  *
941  * This function check the new timstamp-pair(cur_host_time/cur_target_time)or
942  * (cur_qtime_time/cur_target_time)
943  * Return:
944  * HDD_TS_STATUS_WAITING: cur_sync_time or cur_sync_time is 0
945  * HDD_TS_STATUS_READY: cur_target_time/cur_host_time is a valid pair,
946  *    and can be saved
947  * HDD_TS_STATUS_INVALID: cur_target_time/cur_sync_time is a invalid pair,
948  *    should be discard
949  */
950 static
hdd_check_timestamp_status(uint64_t last_target_time,uint64_t last_sync_time,uint64_t cur_target_time,uint64_t cur_sync_time,bool force_sync)951 enum hdd_ts_status hdd_check_timestamp_status(
952 		uint64_t last_target_time,
953 		uint64_t last_sync_time,
954 		uint64_t cur_target_time,
955 		uint64_t cur_sync_time,
956 		bool force_sync)
957 {
958 	uint64_t delta_ns, delta_target_time, delta_sync_time;
959 
960 	/* one or more are not updated, need to wait */
961 	if (cur_target_time == 0 || cur_sync_time == 0)
962 		return HDD_TS_STATUS_WAITING;
963 
964 	/* init value, it's the first time to update the pair */
965 	if (last_target_time == 0 && last_sync_time == 0)
966 		return HDD_TS_STATUS_READY;
967 
968 	/* the new values should be greater than the saved values */
969 	if ((cur_target_time <= last_target_time) ||
970 	    (cur_sync_time <= last_sync_time)) {
971 		hdd_err("Invalid timestamps!last_target_time: %llu;"
972 			"last_sync_time: %llu; cur_target_time: %llu;"
973 			"cur_sync_time: %llu",
974 			last_target_time, last_sync_time,
975 			cur_target_time, cur_sync_time);
976 		return HDD_TS_STATUS_INVALID;
977 	}
978 
979 	delta_target_time = (cur_target_time - last_target_time) *
980 						NSEC_PER_USEC;
981 	delta_sync_time = cur_sync_time - last_sync_time;
982 
983 	/*
984 	 * DO NOT use abs64() , a big uint64 value might be turned to
985 	 * a small int64 value
986 	 */
987 	delta_ns = ((delta_target_time > delta_sync_time) ?
988 			(delta_target_time - delta_sync_time) :
989 			(delta_sync_time - delta_target_time));
990 	hdd_debug("timestamps deviation - delta: %llu ns", delta_ns);
991 	/* the deviation should be smaller than a threshold */
992 	if (!force_sync && delta_ns > MAX_ALLOWED_DEVIATION_NS) {
993 		hdd_debug("Invalid timestamps - delta: %llu ns", delta_ns);
994 		return HDD_TS_STATUS_INVALID;
995 	}
996 	return HDD_TS_STATUS_READY;
997 }
998 
hdd_tsf_is_in_cap(struct hdd_adapter * adapter)999 static inline bool hdd_tsf_is_in_cap(struct hdd_adapter *adapter)
1000 {
1001 	struct hdd_context *hddctx;
1002 
1003 	hddctx = WLAN_HDD_GET_CTX(adapter);
1004 	if (!hddctx)
1005 		return false;
1006 
1007 	return qdf_atomic_read(&hddctx->tsf.cap_tsf_flag) > 0;
1008 }
1009 
1010 /* define 64bit plus/minus to deal with overflow */
hdd_64bit_plus(uint64_t x,int64_t y,uint64_t * ret)1011 static inline int hdd_64bit_plus(uint64_t x, int64_t y, uint64_t *ret)
1012 {
1013 	if ((y < 0 && (-y) > x) ||
1014 	    (y > 0 && (y > U64_MAX - x))) {
1015 		*ret = 0;
1016 		return -EINVAL;
1017 	}
1018 
1019 	*ret = x + y;
1020 	return 0;
1021 }
1022 
hdd_uint64_plus(uint64_t x,uint64_t y,uint64_t * ret)1023 static inline int hdd_uint64_plus(uint64_t x, uint64_t y, uint64_t *ret)
1024 {
1025 	if (!ret)
1026 		return -EINVAL;
1027 
1028 	if (x > (U64_MAX - y)) {
1029 		*ret = 0;
1030 		return -EINVAL;
1031 	}
1032 
1033 	*ret = x + y;
1034 	return 0;
1035 }
1036 
hdd_uint64_minus(uint64_t x,uint64_t y,uint64_t * ret)1037 static inline int hdd_uint64_minus(uint64_t x, uint64_t y, uint64_t *ret)
1038 {
1039 	if (!ret)
1040 		return -EINVAL;
1041 
1042 	if (x < y) {
1043 		*ret = 0;
1044 		return -EINVAL;
1045 	}
1046 
1047 	*ret = x - y;
1048 	return 0;
1049 }
1050 
hdd_get_hosttime_from_targettime(struct hdd_adapter * adapter,uint64_t target_time,uint64_t * host_time)1051 static inline int32_t hdd_get_hosttime_from_targettime(
1052 	struct hdd_adapter *adapter, uint64_t target_time,
1053 	uint64_t *host_time)
1054 {
1055 	struct hdd_vdev_tsf *tsf;
1056 	int32_t ret = -EINVAL;
1057 	int64_t delta32_target;
1058 	bool in_cap_state;
1059 	int64_t normal_interval_target;
1060 
1061 	in_cap_state = hdd_tsf_is_in_cap(adapter);
1062 	tsf = &adapter->tsf;
1063 
1064 	/*
1065 	 * To avoid check the lock when it's not capturing tsf
1066 	 * (the tstamp-pair won't be changed)
1067 	 */
1068 	if (in_cap_state)
1069 		qdf_spin_lock_bh(&tsf->host_target_sync_lock);
1070 
1071 	hdd_wlan_restart_tsf_cap(adapter);
1072 	/* at present, target_time is only 32bit in fact */
1073 	delta32_target = (int64_t)((target_time & U32_MAX) -
1074 			(tsf->last_target_time & U32_MAX));
1075 
1076 	normal_interval_target = WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC *
1077 		qdf_do_div(NSEC_PER_SEC, HOST_TO_TARGET_TIME_RATIO);
1078 
1079 	if (delta32_target <
1080 			(normal_interval_target - OVERFLOW_INDICATOR32))
1081 		delta32_target += OVERFLOW_INDICATOR32;
1082 	else if (delta32_target >
1083 			(OVERFLOW_INDICATOR32 - normal_interval_target))
1084 		delta32_target -= OVERFLOW_INDICATOR32;
1085 
1086 	ret = hdd_64bit_plus(tsf->last_host_time,
1087 			     HOST_TO_TARGET_TIME_RATIO * delta32_target,
1088 			     host_time);
1089 
1090 	if (in_cap_state)
1091 		qdf_spin_unlock_bh(&tsf->host_target_sync_lock);
1092 
1093 	return ret;
1094 }
1095 
hdd_get_targettime_from_hosttime(struct hdd_adapter * adapter,uint64_t host_time,uint64_t * target_time)1096 static inline int32_t hdd_get_targettime_from_hosttime(
1097 	struct hdd_adapter *adapter, uint64_t host_time,
1098 	uint64_t *target_time)
1099 {
1100 	struct hdd_vdev_tsf *tsf;
1101 	int32_t ret = -EINVAL;
1102 	bool in_cap_state;
1103 
1104 	if (!adapter || host_time == 0)
1105 		return ret;
1106 
1107 	tsf = &adapter->tsf;
1108 	in_cap_state = hdd_tsf_is_in_cap(adapter);
1109 	if (in_cap_state)
1110 		qdf_spin_lock_bh(&tsf->host_target_sync_lock);
1111 
1112 	if (host_time < tsf->last_host_time)
1113 		ret = hdd_uint64_minus(tsf->last_target_time,
1114 				       qdf_do_div(tsf->last_host_time -
1115 						  host_time,
1116 						  HOST_TO_TARGET_TIME_RATIO),
1117 				       target_time);
1118 	else
1119 		ret = hdd_uint64_plus(tsf->last_target_time,
1120 				      qdf_do_div(host_time -
1121 						 tsf->last_host_time,
1122 						 HOST_TO_TARGET_TIME_RATIO),
1123 				      target_time);
1124 
1125 	if (in_cap_state)
1126 		qdf_spin_unlock_bh(&tsf->host_target_sync_lock);
1127 
1128 	return ret;
1129 }
1130 
1131 /**
1132  * hdd_get_soctime_from_tsf64time() - return get status
1133  *
1134  * @adapter: Adapter pointer
1135  * @tsf64_time: current tsf64time, us
1136  * @soc_time: current soc time(qtime), ns
1137  *
1138  * This function get current soc time from current tsf64 time
1139  * Returun int32_t value to tell get success or fail.
1140  *
1141  * Return:
1142  * 0:        success
1143  * other: fail
1144  *
1145  */
hdd_get_soctime_from_tsf64time(struct hdd_adapter * adapter,uint64_t tsf64_time,uint64_t * soc_time)1146 static inline int32_t hdd_get_soctime_from_tsf64time(
1147 	struct hdd_adapter *adapter, uint64_t tsf64_time,
1148 	uint64_t *soc_time)
1149 {
1150 	struct hdd_vdev_tsf *tsf;
1151 	int32_t ret = -EINVAL;
1152 	uint64_t delta64_tsf64time;
1153 	uint64_t delta64_soctime;
1154 	bool in_cap_state;
1155 
1156 	in_cap_state = hdd_tsf_is_in_cap(adapter);
1157 	tsf = &adapter->tsf;
1158 
1159 	/*
1160 	 * To avoid check the lock when it's not capturing tsf
1161 	 * (the tstamp-pair won't be changed)
1162 	 */
1163 	if (in_cap_state)
1164 		qdf_spin_lock_bh(&tsf->host_target_sync_lock);
1165 
1166 	/* at present, target_time is 64bit (g_tsf64), us*/
1167 	if (tsf64_time > tsf->last_target_global_tsf_time) {
1168 		delta64_tsf64time = tsf64_time -
1169 				    tsf->last_target_global_tsf_time;
1170 		delta64_soctime = delta64_tsf64time * NSEC_PER_USEC;
1171 
1172 		/* soc_time (ns)*/
1173 		ret = hdd_uint64_plus(tsf->last_tsf_sync_soc_time,
1174 				      delta64_soctime, soc_time);
1175 	} else {
1176 		delta64_tsf64time = tsf->last_target_global_tsf_time -
1177 				    tsf64_time;
1178 		delta64_soctime = delta64_tsf64time * NSEC_PER_USEC;
1179 
1180 		/* soc_time (ns)*/
1181 		ret = hdd_uint64_minus(tsf->last_tsf_sync_soc_time,
1182 				       delta64_soctime, soc_time);
1183 	}
1184 
1185 	if (in_cap_state)
1186 		qdf_spin_unlock_bh(&tsf->host_target_sync_lock);
1187 
1188 	return ret;
1189 }
1190 
1191 /**
1192  * hdd_get_tsftime_from_qtime()
1193  *
1194  * @adapter: Adapter pointer
1195  * @qtime: current qtime, us
1196  * @tsf_time: current tsf time(qtime), us
1197  *
1198  * This function determines current tsf time
1199  * using current qtime
1200  *
1201  * Return: 0 for success or non-zero negative failure code
1202  */
1203 static inline int32_t
hdd_get_tsftime_from_qtime(struct hdd_adapter * adapter,uint64_t qtime,uint64_t * tsf_time)1204 hdd_get_tsftime_from_qtime(struct hdd_adapter *adapter, uint64_t qtime,
1205 			   uint64_t *tsf_time)
1206 {
1207 	struct hdd_vdev_tsf *tsf;
1208 	int32_t ret = -EINVAL;
1209 	uint64_t delta64_tsf64time, tsf_sync_qtime;
1210 	bool in_cap_state;
1211 
1212 	in_cap_state = hdd_tsf_is_in_cap(adapter);
1213 	tsf = &adapter->tsf;
1214 
1215 	/*
1216 	 * To avoid check the lock when it's not capturing tsf
1217 	 * (the tstamp-pair won't be changed)
1218 	 */
1219 	if (in_cap_state)
1220 		qdf_spin_lock_bh(&tsf->host_target_sync_lock);
1221 
1222 	tsf_sync_qtime = tsf->last_tsf_sync_soc_time;
1223 	tsf_sync_qtime = qdf_do_div(tsf_sync_qtime, NSEC_PER_USEC);
1224 
1225 	if (qtime > tsf_sync_qtime) {
1226 		delta64_tsf64time = qtime - tsf_sync_qtime;
1227 		ret = hdd_uint64_plus(tsf->last_target_time,
1228 				      delta64_tsf64time, tsf_time);
1229 	} else {
1230 		delta64_tsf64time = tsf_sync_qtime - qtime;
1231 		ret = hdd_uint64_minus(tsf->last_target_time,
1232 				       delta64_tsf64time, tsf_time);
1233 	}
1234 
1235 	if (in_cap_state)
1236 		qdf_spin_unlock_bh(&tsf->host_target_sync_lock);
1237 
1238 	return ret;
1239 }
1240 
hdd_get_tsf_time(void * adapter_ctx,uint64_t input_time,uint64_t * tsf_time)1241 QDF_STATUS hdd_get_tsf_time(void *adapter_ctx, uint64_t input_time,
1242 			    uint64_t *tsf_time)
1243 {
1244 	struct hdd_adapter *adapter;
1245 	uint64_t qtime;
1246 
1247 	/* Sanity check on inputs */
1248 	if (unlikely((!adapter_ctx) || (!input_time))) {
1249 		hdd_err("Invalid param passed");
1250 		return QDF_STATUS_E_FAILURE;
1251 	}
1252 
1253 	adapter = (struct hdd_adapter *)adapter_ctx;
1254 	if (unlikely(adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) {
1255 		hdd_err("Magic cookie(%x) for adapter sanity verification is invalid",
1256 			adapter->magic);
1257 		return QDF_STATUS_E_FAILURE;
1258 	}
1259 
1260 	qtime = qdf_log_timestamp_to_usecs(input_time);
1261 	hdd_get_tsftime_from_qtime(adapter, qtime, tsf_time);
1262 	return QDF_STATUS_SUCCESS;
1263 }
1264 
hdd_capture_tsf_timer_expired_handler(void * arg)1265 static void hdd_capture_tsf_timer_expired_handler(void *arg)
1266 {
1267 	uint32_t tsf_op_resp;
1268 	struct hdd_adapter *adapter;
1269 
1270 	if (!arg)
1271 		return;
1272 
1273 	adapter = (struct hdd_adapter *)arg;
1274 	hdd_capture_tsf_internal(adapter, &tsf_op_resp, 1);
1275 }
1276 
1277 #ifdef WLAN_FEATURE_TSF_ACCURACY
1278 #define WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC 50
1279 #define WLAN_HDD_TOGGLE_GPIO_BACKOFF_MAX_USEC 200
1280 #define WLAN_HDD_PULSE_WIDTH_MSEC 1
1281 
1282 /**
1283  * hdd_get_tsf_accuracy_context() - Return the TSF Accuracy config params
1284  * @adapter: Pointer to adapter
1285  *
1286  * This function validates feature config parameters
1287  *
1288  * Return: Pointer to TSF Accuracy feature configs
1289  */
1290 static struct wlan_fwol_tsf_accuracy_configs *
hdd_get_tsf_accuracy_context(struct hdd_adapter * adapter)1291 hdd_get_tsf_accuracy_context(struct hdd_adapter *adapter)
1292 {
1293 	struct wlan_fwol_tsf_accuracy_configs *configs = NULL;
1294 	struct hdd_context *hddctx;
1295 	int status;
1296 
1297 	hddctx = WLAN_HDD_GET_CTX(adapter);
1298 	if (!hddctx) {
1299 		hdd_err("invalid hdd context");
1300 		return NULL;
1301 	}
1302 
1303 	if (hddctx->tsf.tsf_accuracy_context &&
1304 	    hddctx->tsf.tsf_accuracy_context != adapter)
1305 		return NULL;
1306 
1307 	status = ucfg_fwol_get_tsf_accuracy_configs(hddctx->psoc, &configs);
1308 	if (status == QDF_STATUS_E_FAILURE)
1309 		return NULL;
1310 
1311 	if (!configs || !configs->enable ||
1312 	    (configs->periodic_pulse_gpio == TSF_GPIO_PIN_INVALID &&
1313 	     configs->sync_gpio == TSF_GPIO_PIN_INVALID))
1314 		return NULL;
1315 
1316 	return configs;
1317 }
1318 
1319 /**
1320  * hdd_tsf_gpio_pulse() - Raise pulse of WLAN_HDD_PULSE_WIDTH_MSEC on gpio
1321  * @gpio_num: GPIO number
1322  *
1323  * Return: None
1324  */
hdd_tsf_gpio_pulse(uint32_t gpio_num)1325 static void hdd_tsf_gpio_pulse(uint32_t gpio_num)
1326 {
1327 	if (gpio_num == TSF_GPIO_PIN_INVALID)
1328 		return;
1329 
1330 	gpio_set_value(gpio_num, OUTPUT_HIGH);
1331 	udelay(WLAN_HDD_PULSE_WIDTH_MSEC * USEC_PER_MSEC);
1332 	gpio_set_value(gpio_num, OUTPUT_LOW);
1333 }
1334 
1335 /**
1336  * hdd_tsf_gpio_timer_expired_handler() - Handle periodic TSF periodic expiry
1337  * @arg: Pointer to qdf_hrtimer_data_t
1338  *
1339  * Raise GPIO pulse on TSF time cycle completion and schedules hrtimer for
1340  * next cycle. Also, monitors drift between Host time and TSF time.
1341  * This data will be used for scheduling hrtimer expiry.
1342  *
1343  * Return:
1344  *      QDF_HRTIMER_RESTART - On completion of TSF cycle processing
1345  *      QDF_HRTIMER_NORESTART - On error
1346  */
1347 static enum qdf_hrtimer_restart_status
hdd_tsf_gpio_timer_expired_handler(qdf_hrtimer_data_t * arg)1348 hdd_tsf_gpio_timer_expired_handler(qdf_hrtimer_data_t *arg)
1349 {
1350 	struct hdd_adapter *adapter;
1351 	struct hdd_vdev_tsf *tsf;
1352 	struct wlan_fwol_tsf_accuracy_configs *configs;
1353 	qdf_ktime_t cur_qtime, spin_until, next_ktime;
1354 	uint64_t qtime;
1355 	uint64_t tsf_time_us;
1356 	uint32_t elapsed_time_us;
1357 	uint32_t remaining_time_us;
1358 	uint32_t delta_interval_us;
1359 
1360 	tsf = qdf_container_of(arg, struct hdd_vdev_tsf,
1361 			       host_trigger_gpio_timer);
1362 	if (!tsf)
1363 		return QDF_HRTIMER_NORESTART;
1364 
1365 	adapter = qdf_container_of(tsf, struct hdd_adapter, tsf);
1366 
1367 	configs = hdd_get_tsf_accuracy_context(adapter);
1368 	if (!configs)
1369 		return QDF_HRTIMER_NORESTART;
1370 
1371 	/* Get current System and TSF mapping */
1372 	qtime = qdf_log_timestamp_to_usecs(qdf_get_log_timestamp());
1373 	hdd_get_tsftime_from_qtime(adapter, qtime, &tsf_time_us);
1374 	elapsed_time_us = (uint32_t)
1375 		(tsf_time_us % (configs->pulse_interval_ms * USEC_PER_MSEC));
1376 	remaining_time_us =
1377 		(configs->pulse_interval_ms * USEC_PER_MSEC) - elapsed_time_us;
1378 
1379 	/* Skip raising GPIO pulse in case of TSF cycle already completed */
1380 	if (elapsed_time_us < remaining_time_us) {
1381 		next_ktime = qdf_ns_to_ktime(NSEC_PER_USEC *
1382 			((configs->pulse_interval_ms * USEC_PER_MSEC) -
1383 			 WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC -
1384 			 elapsed_time_us));
1385 		hdd_debug("TSF_Accuracy: skip GPIO pulse tsf_time_us:%llu",
1386 			  tsf_time_us);
1387 		goto end;
1388 	}
1389 
1390 	if (remaining_time_us > WLAN_HDD_TOGGLE_GPIO_BACKOFF_MAX_USEC)
1391 		goto skip;
1392 	/*
1393 	 * Expect WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC seconds of backoff always
1394 	 * for TSF time to complete a cycle of given interval.
1395 	 * Hence run backoff busy wait and then trigger GPIO
1396 	 */
1397 	cur_qtime = qdf_ns_to_ktime(qtime * NSEC_PER_USEC);
1398 	spin_until = qdf_ktime_add(cur_qtime,
1399 				   qdf_ns_to_ktime(remaining_time_us *
1400 				    NSEC_PER_USEC));
1401 	do {
1402 		qtime = qdf_log_timestamp_to_usecs(qdf_get_log_timestamp());
1403 		cur_qtime = qdf_ns_to_ktime(qtime * NSEC_PER_USEC);
1404 	} while (ktime_compare(cur_qtime, spin_until) < 0);
1405 
1406 	/* Toggle GPIO */
1407 	hdd_tsf_gpio_pulse(configs->periodic_pulse_gpio);
1408 
1409 	/* Check current system and TSF mapping for logging */
1410 	hdd_get_tsftime_from_qtime(adapter, qtime, &tsf_time_us);
1411 
1412 	hdd_debug("TSF_Accuracy: GPIO toggled log_time_us:%llu, tsf_time_us:%llu, slept_us:%d",
1413 		  qtime, tsf_time_us, remaining_time_us);
1414 
1415 	/*
1416 	 *  Schedule next GPIO toggle by adding to last expiry. Monitor drift
1417 	 *  and adjust next expiry time based on system and TSF clock
1418 	 *  difference.
1419 	 */
1420 skip:
1421 	if (remaining_time_us > WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC) {
1422 		delta_interval_us = remaining_time_us -
1423 			WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC;
1424 		next_ktime = qdf_ns_to_ktime(NSEC_PER_USEC *
1425 					     ((configs->pulse_interval_ms *
1426 					       USEC_PER_MSEC) +
1427 					     delta_interval_us));
1428 	} else {
1429 		next_ktime = configs->pulse_interval_ms;
1430 	}
1431 end:
1432 	qdf_hrtimer_add_expires(&adapter->tsf.host_trigger_gpio_timer,
1433 				next_ktime);
1434 
1435 	return QDF_HRTIMER_RESTART;
1436 }
1437 
1438 /**
1439  * hdd_tsf_setup_gpio_toggle() - Schedules hrtimer for TSF periodic processing.
1440  * @adapter: Pointer to adapter
1441  *
1442  * Schedule a TSF time domain periodic pulse handling and also indicate a
1443  * TSF sync done by toggling GPIO.
1444  *
1445  * Return: None
1446  */
hdd_tsf_setup_gpio_toggle(struct hdd_adapter * adapter)1447 static void hdd_tsf_setup_gpio_toggle(struct hdd_adapter *adapter)
1448 {
1449 	static uint32_t gpio_state = OUTPUT_LOW;
1450 	uint64_t tsf_time_us;
1451 	uint64_t qtime;
1452 	uint32_t elapsed_time_us;
1453 	uint32_t remaining_time_us;
1454 	qdf_ktime_t cur_ktime, next_ktime;
1455 	struct wlan_fwol_tsf_accuracy_configs *configs;
1456 	qdf_hrtimer_data_t *gtimer;
1457 
1458 	configs = hdd_get_tsf_accuracy_context(adapter);
1459 	if (!configs)
1460 		return;
1461 
1462 	gtimer = &adapter->tsf.host_trigger_gpio_timer;
1463 
1464 	/* Get current System and TSF mapping */
1465 	cur_ktime = qdf_ktime_get();
1466 	qtime = qdf_log_timestamp_to_usecs(qdf_get_log_timestamp());
1467 	hdd_get_tsftime_from_qtime(adapter, qtime, &tsf_time_us);
1468 
1469 	if (configs->sync_gpio != TSF_GPIO_PIN_INVALID) {
1470 		if (gpio_state == OUTPUT_LOW)
1471 			gpio_state = OUTPUT_HIGH;
1472 		else
1473 			gpio_state = OUTPUT_LOW;
1474 		gpio_set_value(configs->sync_gpio, gpio_state);
1475 	}
1476 
1477 	hdd_debug("TSF_Accuracy: TSF sync done system_time_us:%llu, log_time_us:%llu, tsf_time_us:%llu",
1478 		  qdf_ktime_to_us(cur_ktime), qtime, tsf_time_us);
1479 
1480 	/* Start timer if it is not scheduled yet */
1481 	if (!(qdf_hrtimer_is_queued(gtimer) ||
1482 	      qdf_hrtimer_callback_running(gtimer))) {
1483 		/*
1484 		 * Take out WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC as backoff timer
1485 		 * which is taken care by hrtimer handler
1486 		 */
1487 		elapsed_time_us = (uint32_t)(tsf_time_us % USEC_PER_SEC);
1488 		remaining_time_us = USEC_PER_SEC - elapsed_time_us;
1489 		if (remaining_time_us <= WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC)
1490 			return;
1491 		next_ktime = qdf_ktime_add(cur_ktime,
1492 					   qdf_ns_to_ktime((remaining_time_us -
1493 			WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC) * NSEC_PER_USEC));
1494 		qdf_hrtimer_start(gtimer, next_ktime, QDF_HRTIMER_MODE_ABS);
1495 	}
1496 }
1497 
1498 /**
1499  * hdd_tsf_regular_gpio_pulse_init() - Initialize TSF Accuracy feature
1500  * @adapter: Pointer to adapter
1501  *
1502  * Return: None
1503  */
hdd_tsf_regular_gpio_pulse_init(struct hdd_adapter * adapter)1504 static void hdd_tsf_regular_gpio_pulse_init(struct hdd_adapter *adapter)
1505 {
1506 	struct wlan_fwol_tsf_accuracy_configs *configs;
1507 	struct hdd_context *hddctx;
1508 
1509 	hddctx = WLAN_HDD_GET_CTX(adapter);
1510 	if (!hddctx) {
1511 		hdd_err("invalid hdd context");
1512 		return;
1513 	}
1514 
1515 	configs = hdd_get_tsf_accuracy_context(adapter);
1516 	if (!configs)
1517 		goto fail;
1518 
1519 	qdf_hrtimer_init(&adapter->tsf.host_trigger_gpio_timer,
1520 			 hdd_tsf_gpio_timer_expired_handler,
1521 			 QDF_CLOCK_MONOTONIC, QDF_HRTIMER_MODE_ABS,
1522 			 QDF_CONTEXT_HARDWARE);
1523 
1524 	if (configs->periodic_pulse_gpio != TSF_GPIO_PIN_INVALID) {
1525 		if (gpio_request(configs->periodic_pulse_gpio,
1526 				 "tsf_periodic_pulse"))
1527 			goto fail;
1528 		if (gpio_direction_output(configs->periodic_pulse_gpio,
1529 					  OUTPUT_LOW))
1530 			goto fail_free_pulse_gpio;
1531 	}
1532 
1533 	if (configs->sync_gpio != TSF_GPIO_PIN_INVALID) {
1534 		if (gpio_request(configs->sync_gpio, "tsf_sync_toggle"))
1535 			goto fail_free_pulse_gpio;
1536 		if (gpio_direction_output(configs->sync_gpio, OUTPUT_LOW))
1537 			goto fail_free_gpio;
1538 	}
1539 
1540 	hddctx->tsf.tsf_accuracy_context = adapter;
1541 	hdd_debug("TSF_Accuracy: Feature initialization success");
1542 	return;
1543 
1544 fail_free_gpio:
1545 	gpio_free(configs->sync_gpio);
1546 fail_free_pulse_gpio:
1547 	if (configs->periodic_pulse_gpio != TSF_GPIO_PIN_INVALID)
1548 		gpio_free(configs->periodic_pulse_gpio);
1549 fail:
1550 	hdd_err("TSF_Accuracy: Feature init failed");
1551 }
1552 
1553 /**
1554  * hdd_tsf_regular_gpio_pulse_deinit() - Deactivate TSF Accuracy feature
1555  * @adapter: Pointer to adapter
1556  *
1557  * Return: None
1558  */
hdd_tsf_regular_gpio_pulse_deinit(struct hdd_adapter * adapter)1559 static void hdd_tsf_regular_gpio_pulse_deinit(struct hdd_adapter *adapter)
1560 {
1561 	struct wlan_fwol_tsf_accuracy_configs *configs = NULL;
1562 	struct hdd_context *hddctx;
1563 
1564 	hddctx = WLAN_HDD_GET_CTX(adapter);
1565 	if (!hddctx) {
1566 		hdd_err("invalid hdd context");
1567 		return;
1568 	}
1569 
1570 	if (hddctx->tsf.tsf_accuracy_context != adapter)
1571 		return;
1572 
1573 	configs = hdd_get_tsf_accuracy_context(adapter);
1574 	if (!configs)
1575 		return;
1576 
1577 	qdf_hrtimer_cancel(&adapter->tsf.host_trigger_gpio_timer);
1578 
1579 	if (configs->periodic_pulse_gpio != TSF_GPIO_PIN_INVALID)
1580 		gpio_free(configs->periodic_pulse_gpio);
1581 	if (configs->sync_gpio != TSF_GPIO_PIN_INVALID) {
1582 		gpio_set_value(configs->sync_gpio, OUTPUT_LOW);
1583 		gpio_free(configs->sync_gpio);
1584 	}
1585 
1586 	hddctx->tsf.tsf_accuracy_context = NULL;
1587 }
1588 #else
hdd_tsf_setup_gpio_toggle(struct hdd_adapter * adapter)1589 static void hdd_tsf_setup_gpio_toggle(struct hdd_adapter *adapter)
1590 {
1591 }
1592 
hdd_tsf_regular_gpio_pulse_init(struct hdd_adapter * adapter)1593 static void hdd_tsf_regular_gpio_pulse_init(struct hdd_adapter *adapter)
1594 {
1595 }
1596 
hdd_tsf_regular_gpio_pulse_deinit(struct hdd_adapter * adapter)1597 static void hdd_tsf_regular_gpio_pulse_deinit(struct hdd_adapter *adapter)
1598 {
1599 }
1600 #endif
1601 
1602 #ifndef WLAN_FEATURE_TSF_PLUS_NOIRQ
1603 #if !defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) && \
1604 	!defined(WLAN_FEATURE_TSF_TIMER_SYNC)
1605 
hdd_tsf_captured_irq_handler(int irq,void * arg)1606 static irqreturn_t hdd_tsf_captured_irq_handler(int irq, void *arg)
1607 {
1608 	struct hdd_adapter *adapter;
1609 	struct hdd_context *hdd_ctx;
1610 	uint64_t host_time;
1611 	char *name = NULL;
1612 
1613 	if (!arg)
1614 		return IRQ_NONE;
1615 
1616 	if (irq != tsf_gpio_irq_num)
1617 		return IRQ_NONE;
1618 
1619 	hdd_ctx = (struct hdd_context *)arg;
1620 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
1621 
1622 	adapter = hdd_ctx->tsf.cap_tsf_context;
1623 	if (!adapter)
1624 		return IRQ_HANDLED;
1625 
1626 	if (!hdd_tsf_is_initialized(adapter)) {
1627 		hdd_err("tsf is not init, ignore irq");
1628 		return IRQ_HANDLED;
1629 	}
1630 
1631 	hdd_update_timestamp(adapter, 0, host_time);
1632 	if (adapter->dev)
1633 		name = adapter->dev->name;
1634 
1635 	hdd_debug("irq: %d - iface: %s - host_time: %llu",
1636 		  irq, (!name ? "none" : name), host_time);
1637 
1638 	return IRQ_HANDLED;
1639 }
1640 #endif
1641 #endif
1642 
hdd_capture_req_timer_expired_handler(void * arg)1643 void hdd_capture_req_timer_expired_handler(void *arg)
1644 {
1645 	struct hdd_adapter *adapter;
1646 	struct hdd_context *hdd_ctx;
1647 	struct hdd_vdev_tsf *tsf;
1648 	QDF_TIMER_STATE capture_req_timer_status;
1649 	qdf_mc_timer_t *sync_timer;
1650 	int interval;
1651 	int ret;
1652 
1653 	if (!arg)
1654 		return;
1655 	adapter = (struct hdd_adapter *)arg;
1656 
1657 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1658 	if (!hdd_ctx) {
1659 		hdd_warn("invalid hdd context");
1660 		return;
1661 	}
1662 	tsf = &adapter->tsf;
1663 	if (!hdd_tsf_is_initialized(adapter)) {
1664 		hdd_warn("tsf not init");
1665 		return;
1666 	}
1667 
1668 	qdf_spin_lock_bh(&tsf->host_target_sync_lock);
1669 	tsf->cur_host_time = 0;
1670 	tsf->cur_target_time = 0;
1671 	qdf_spin_unlock_bh(&tsf->host_target_sync_lock);
1672 
1673 	ret = hdd_tsf_reset_gpio(adapter);
1674 	if (0 != ret)
1675 		hdd_info("reset tsf gpio fail");
1676 
1677 	hdd_ctx->tsf.cap_tsf_context = NULL;
1678 	qdf_atomic_set(&hdd_ctx->tsf.cap_tsf_flag, 0);
1679 
1680 	sync_timer = &tsf->host_target_sync_timer;
1681 	capture_req_timer_status =
1682 		qdf_mc_timer_get_current_state(sync_timer);
1683 
1684 	if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) {
1685 		hdd_warn("invalid timer status");
1686 		return;
1687 	}
1688 
1689 	interval = WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL * MSEC_PER_SEC;
1690 	qdf_mc_timer_start(sync_timer, interval);
1691 }
1692 
1693 #if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) || \
1694 	defined(WLAN_FEATURE_TSF_TIMER_SYNC)
hdd_update_timestamp(struct hdd_adapter * adapter)1695 static void hdd_update_timestamp(struct hdd_adapter *adapter)
1696 {
1697 	int interval = 0;
1698 	enum hdd_ts_status sync_status;
1699 	struct hdd_vdev_tsf *tsf;
1700 
1701 	if (!adapter)
1702 		return;
1703 
1704 	tsf = &adapter->tsf;
1705 	/* on ADREASTEA ach, Qtime is used to sync host and tsf time as a
1706 	 * intermedia there is no IRQ to sync up TSF-HOST, so host time in ns
1707 	 * and target in us will be updated at the same time in WMI command
1708 	 * callback
1709 	 */
1710 
1711 	qdf_spin_lock_bh(&tsf->host_target_sync_lock);
1712 	sync_status =
1713 		  hdd_check_timestamp_status(tsf->last_target_time,
1714 					     tsf->last_tsf_sync_soc_time,
1715 					     tsf->cur_target_time,
1716 					     tsf->cur_tsf_sync_soc_time,
1717 					     tsf->host_target_sync_force);
1718 	if (tsf->host_target_sync_force)
1719 		tsf->host_target_sync_force = false;
1720 
1721 	hdd_debug("sync_status %d", sync_status);
1722 	switch (sync_status) {
1723 	case HDD_TS_STATUS_INVALID:
1724 		if (++tsf->continuous_error_count <
1725 		    MAX_CONTINUOUS_ERROR_CNT) {
1726 			interval =
1727 				WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS;
1728 			tsf->cur_target_time = 0;
1729 			tsf->cur_tsf_sync_soc_time = 0;
1730 			break;
1731 		}
1732 		hdd_debug("Reach the max continuous error count");
1733 
1734 		/* If reach MAX_CONTINUOUS_ERROR_CNT, treat it as valid pair */
1735 		fallthrough;
1736 	case HDD_TS_STATUS_READY:
1737 		tsf->last_target_time = tsf->cur_target_time;
1738 		tsf->last_target_global_tsf_time =
1739 			tsf->cur_target_global_tsf_time;
1740 		tsf->last_tsf_sync_soc_time =
1741 				tsf->cur_tsf_sync_soc_time;
1742 		tsf->cur_target_time = 0;
1743 		tsf->cur_target_global_tsf_time = 0;
1744 		tsf->cur_tsf_sync_soc_time = 0;
1745 		hdd_debug("ts-pair updated: target: %llu; g_target:%llu, Qtime: %llu",
1746 			  tsf->last_target_time,
1747 			  tsf->last_target_global_tsf_time,
1748 			  tsf->last_tsf_sync_soc_time);
1749 
1750 		/*
1751 		 * TSF-HOST need to be updated in at most
1752 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, it couldn't be achieved
1753 		 * if the timer interval is also
1754 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, due to processing or
1755 		 * schedule delay. So deduct several seconds from
1756 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC.
1757 		 * Without this change, hdd_get_hosttime_from_targettime() will
1758 		 * get wrong host time when it's longer than
1759 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last
1760 		 * TSF-HOST update.
1761 		 */
1762 
1763 		if (tsf->dynamic_tsf_sync_interval)
1764 			interval = tsf->dynamic_tsf_sync_interval;
1765 		else
1766 			interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC -
1767 				    CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC;
1768 
1769 		tsf->continuous_error_count = 0;
1770 		tsf->continuous_cap_retry_count = 0;
1771 		hdd_debug("ts-pair updated: interval: %d",
1772 			  interval);
1773 		break;
1774 	case HDD_TS_STATUS_WAITING:
1775 		interval = 0;
1776 		hdd_warn("TS status is waiting due to one or more pair not updated");
1777 		break;
1778 	}
1779 	qdf_spin_unlock_bh(&tsf->host_target_sync_lock);
1780 
1781 	hdd_tsf_setup_gpio_toggle(adapter);
1782 
1783 	if (interval > 0)
1784 		qdf_mc_timer_start(&tsf->host_target_sync_timer,
1785 				   interval);
1786 }
1787 
__hdd_wlan_tsf_show(struct device * dev,struct device_attribute * attr,char * buf)1788 static ssize_t __hdd_wlan_tsf_show(struct device *dev,
1789 				   struct device_attribute *attr, char *buf)
1790 {
1791 	struct hdd_station_ctx *hdd_sta_ctx;
1792 	struct hdd_adapter *adapter;
1793 	struct hdd_context *hdd_ctx;
1794 	uint64_t tsf_sync_qtime, host_time, reg_qtime, qtime, target_time;
1795 	ssize_t size;
1796 	uint8_t *mac;
1797 
1798 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
1799 
1800 	adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
1801 	if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC)
1802 		return scnprintf(buf, PAGE_SIZE, "Invalid device\n");
1803 
1804 	if (!hdd_get_th_sync_status(adapter))
1805 		return scnprintf(buf, PAGE_SIZE,
1806 				 "TSF sync is not initialized\n");
1807 
1808 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
1809 	if (!hdd_cm_is_vdev_associated(adapter->deflink) &&
1810 	    (adapter->device_mode == QDF_STA_MODE ||
1811 	    adapter->device_mode == QDF_P2P_CLIENT_MODE))
1812 		return scnprintf(buf, PAGE_SIZE, "NOT connected\n");
1813 
1814 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1815 
1816 	if (!hdd_ctx)
1817 		return scnprintf(buf, PAGE_SIZE, "Invalid HDD context\n");
1818 
1819 	reg_qtime = qdf_get_log_timestamp();
1820 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
1821 
1822 	qtime = qdf_log_timestamp_to_usecs(reg_qtime);
1823 	do_div(host_time, NSEC_PER_USEC);
1824 	hdd_get_tsftime_from_qtime(adapter, qtime, &target_time);
1825 	tsf_sync_qtime = adapter->tsf.last_tsf_sync_soc_time;
1826 	do_div(tsf_sync_qtime, NSEC_PER_USEC);
1827 
1828 	if (adapter->device_mode == QDF_STA_MODE ||
1829 	    adapter->device_mode == QDF_P2P_CLIENT_MODE) {
1830 		mac = hdd_sta_ctx->conn_info.bssid.bytes;
1831 		size = scnprintf(buf, PAGE_SIZE,
1832 				 "%s%llu %llu " QDF_MAC_ADDR_FMT
1833 				 " %llu %llu %llu\n",
1834 				 buf, adapter->tsf.last_target_time,
1835 				 tsf_sync_qtime,
1836 				 QDF_MAC_ADDR_REF(mac),
1837 				 qtime, host_time, target_time);
1838 	} else {
1839 		mac = adapter->mac_addr.bytes;
1840 		size = scnprintf(buf, PAGE_SIZE,
1841 				 "%s%llu %llu " QDF_MAC_ADDR_FMT
1842 				 " %llu %llu %llu\n",
1843 				 buf, adapter->tsf.last_target_time,
1844 				 tsf_sync_qtime,
1845 				 QDF_MAC_ADDR_REF(mac),
1846 				 qtime, host_time, target_time);
1847 	}
1848 
1849 	return size;
1850 }
1851 
hdd_update_tsf(struct hdd_adapter * adapter,uint64_t tsf)1852 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
1853 {
1854 	struct hdd_tsf_op_response tsf_op_resp;
1855 
1856 	hdd_indicate_tsf_internal(adapter, &tsf_op_resp);
1857 	hdd_update_timestamp(adapter);
1858 }
1859 #else
hdd_update_timestamp(struct hdd_adapter * adapter,uint64_t target_time,uint64_t host_time)1860 static void hdd_update_timestamp(struct hdd_adapter *adapter,
1861 				 uint64_t target_time, uint64_t host_time)
1862 {
1863 	int interval = 0;
1864 	enum hdd_ts_status sync_status;
1865 	struct hdd_vdev_tsf	*tsf;
1866 	if (!adapter)
1867 		return;
1868 	tsf = &adapter->tsf;
1869 	/* host time is updated in IRQ context, it's always before target time,
1870 	 * and so no need to try update last_host_time at present;
1871 	 * since the interval of capturing TSF
1872 	 * (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC) is long enough, host and target
1873 	 * time are updated in pairs, and one by one, we can return here to
1874 	 * avoid requiring spin lock, and to speed up the IRQ processing.
1875 	 */
1876 	if (host_time > 0)
1877 		tsf->cur_host_time = host_time;
1878 
1879 	qdf_spin_lock_bh(&tsf->host_target_sync_lock);
1880 	if (target_time > 0)
1881 		tsf->cur_target_time = target_time;
1882 
1883 	sync_status =
1884 		  hdd_check_timestamp_status(tsf->last_target_time,
1885 					     tsf->last_host_time,
1886 					     tsf->cur_target_time,
1887 					     tsf->cur_host_time,
1888 					     tsf->host_target_sync_force);
1889 	if (tsf->host_target_sync_force)
1890 		tsf->host_target_sync_force = false;
1891 
1892 	hdd_debug("sync_status %d", sync_status);
1893 	switch (sync_status) {
1894 	case HDD_TS_STATUS_INVALID:
1895 		if (++tsf->continuous_error_count <
1896 		    MAX_CONTINUOUS_ERROR_CNT) {
1897 			interval =
1898 				WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS;
1899 			tsf->cur_target_time = 0;
1900 			tsf->cur_host_time = 0;
1901 			break;
1902 		}
1903 		hdd_warn("Reach the max continuous error count");
1904 		/*
1905 		 * fall through:
1906 		 * If reach MAX_CONTINUOUS_ERROR_CNT, treat it as a
1907 		 * valid pair
1908 		 */
1909 	case HDD_TS_STATUS_READY:
1910 		tsf->last_target_time = tsf->cur_target_time;
1911 		tsf->last_host_time = tsf->cur_host_time;
1912 		tsf->cur_target_time = 0;
1913 		tsf->cur_host_time = 0;
1914 		hdd_debug("ts-pair updated: target: %llu; host: %llu",
1915 			  tsf->last_target_time,
1916 			  tsf->last_host_time);
1917 
1918 		/*
1919 		 * TSF-HOST need to be updated in at most
1920 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, it couldn't be achieved
1921 		 * if the timer interval is also
1922 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, due to processing or
1923 		 * schedule delay. So deduct several seconds from
1924 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC.
1925 		 * Without this change, hdd_get_hosttime_from_targettime() will
1926 		 * get wrong host time when it's longer than
1927 		 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last
1928 		 * TSF-HOST update.
1929 		 */
1930 		interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC -
1931 			    CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC;
1932 		if (adapter->device_mode == QDF_SAP_MODE ||
1933 		    adapter->device_mode == QDF_P2P_GO_MODE) {
1934 			interval *= WLAN_HDD_SOFTAP_INTERVAL_TIMES;
1935 		}
1936 
1937 		tsf->continuous_error_count = 0;
1938 		tsf->continuous_cap_retry_count = 0;
1939 		hdd_debug("ts-pair updated: interval: %d",
1940 			  interval);
1941 		break;
1942 	case HDD_TS_STATUS_WAITING:
1943 		interval = 0;
1944 		hdd_warn("TS status is waiting due to one or more pair not updated");
1945 
1946 		if (!target_time && !host_time)
1947 			interval = hdd_wlan_retry_tsf_cap(adapter);
1948 		break;
1949 	}
1950 	qdf_spin_unlock_bh(&tsf->host_target_sync_lock);
1951 
1952 	if (interval > 0)
1953 		qdf_mc_timer_start(&tsf->host_target_sync_timer,
1954 				   interval);
1955 }
1956 
__hdd_wlan_tsf_show(struct device * dev,struct device_attribute * attr,char * buf)1957 static ssize_t __hdd_wlan_tsf_show(struct device *dev,
1958 				   struct device_attribute *attr, char *buf)
1959 {
1960 	struct hdd_station_ctx *hdd_sta_ctx;
1961 	struct hdd_adapter *adapter;
1962 	struct hdd_context *hdd_ctx;
1963 	ssize_t size;
1964 	uint64_t host_time, target_time;
1965 	uint8_t *mac;
1966 
1967 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
1968 
1969 	adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
1970 	if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC)
1971 		return scnprintf(buf, PAGE_SIZE, "Invalid device\n");
1972 
1973 	if (!hdd_get_th_sync_status(adapter))
1974 		return scnprintf(buf, PAGE_SIZE,
1975 				 "TSF sync is not initialized\n");
1976 
1977 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink);
1978 	if (!hdd_cm_is_vdev_associated(adapter->deflink) &&
1979 	    (adapter->device_mode == QDF_STA_MODE ||
1980 	    adapter->device_mode == QDF_P2P_CLIENT_MODE))
1981 		return scnprintf(buf, PAGE_SIZE, "NOT connected\n");
1982 
1983 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1984 	if (!hdd_ctx)
1985 		return scnprintf(buf, PAGE_SIZE, "Invalid HDD context\n");
1986 
1987 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
1988 
1989 	if (hdd_get_targettime_from_hosttime(adapter, host_time,
1990 					     &target_time)) {
1991 		size = scnprintf(buf, PAGE_SIZE, "Invalid timestamp\n");
1992 	} else {
1993 		if (adapter->device_mode == QDF_STA_MODE ||
1994 		    adapter->device_mode == QDF_P2P_CLIENT_MODE) {
1995 			mac = hdd_sta_ctx->conn_info.bssid.bytes;
1996 			size = scnprintf(buf, PAGE_SIZE,
1997 					 "%s%llu %llu " QDF_MAC_ADDR_FMT "\n",
1998 					 buf, target_time, host_time,
1999 					 QDF_MAC_ADDR_REF(mac));
2000 		} else {
2001 			mac = adapter->mac_addr.bytes;
2002 			size = scnprintf(buf, PAGE_SIZE,
2003 					 "%s%llu %llu " QDF_MAC_ADDR_FMT "\n",
2004 					 buf, target_time, host_time,
2005 					 QDF_MAC_ADDR_REF(mac));
2006 		}
2007 	}
2008 
2009 	return size;
2010 }
2011 
hdd_update_tsf(struct hdd_adapter * adapter,uint64_t tsf)2012 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
2013 {
2014 	struct hdd_tsf_op_response tsf_op_resp;
2015 
2016 	hdd_indicate_tsf_internal(adapter, &tsf_op_resp);
2017 	hdd_update_timestamp(adapter, tsf, 0);
2018 }
2019 #endif
2020 
hdd_wlan_tsf_show(struct device * dev,struct device_attribute * attr,char * buf)2021 static ssize_t hdd_wlan_tsf_show(struct device *dev,
2022 				 struct device_attribute *attr, char *buf)
2023 {
2024 	struct net_device *net_dev = container_of(dev, struct net_device, dev);
2025 	struct osif_vdev_sync *vdev_sync;
2026 	ssize_t err_size;
2027 
2028 	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
2029 	if (err_size)
2030 		return err_size;
2031 
2032 	err_size = __hdd_wlan_tsf_show(dev, attr, buf);
2033 
2034 	osif_vdev_sync_op_stop(vdev_sync);
2035 
2036 	return err_size;
2037 }
2038 
2039 static DEVICE_ATTR(tsf, 0444, hdd_wlan_tsf_show, NULL);
2040 
hdd_tsf_sync_init(struct hdd_adapter * adapter)2041 static enum hdd_tsf_op_result hdd_tsf_sync_init(struct hdd_adapter *adapter)
2042 {
2043 	QDF_STATUS ret;
2044 	struct hdd_context *hddctx;
2045 	struct net_device *net_dev;
2046 	uint64_t host_time, qtime;
2047 
2048 	if (!adapter)
2049 		return HDD_TSF_OP_FAIL;
2050 
2051 	hddctx = WLAN_HDD_GET_CTX(adapter);
2052 	if (!hddctx) {
2053 		hdd_err("invalid hdd context");
2054 		return HDD_TSF_OP_FAIL;
2055 	}
2056 
2057 	if (!qdf_atomic_read(&hddctx->tsf.tsf_ready_flag)) {
2058 		hdd_err("TSF feature has NOT been initialized");
2059 		return HDD_TSF_OP_FAIL;
2060 	}
2061 
2062 	if (!adapter->tsf.enable_dynamic_tsf_sync) {
2063 		hdd_debug("TSF sync feature not enabled");
2064 		return HDD_TSF_OP_FAIL;
2065 	}
2066 
2067 	if (hdd_get_th_sync_status(adapter)) {
2068 		hdd_err("Host Target sync has been initialized!!");
2069 		return HDD_TSF_OP_SUCC;
2070 	}
2071 
2072 	qdf_spinlock_create(&adapter->tsf.host_target_sync_lock);
2073 
2074 	hdd_reset_timestamps(adapter);
2075 
2076 	ret = qdf_mc_timer_init(&adapter->tsf.host_target_sync_timer,
2077 				QDF_TIMER_TYPE_SW,
2078 				hdd_capture_tsf_timer_expired_handler,
2079 				(void *)adapter);
2080 	if (ret != QDF_STATUS_SUCCESS) {
2081 		hdd_err("Failed to init target timer, ret: %d", ret);
2082 		goto fail;
2083 	}
2084 
2085 	ret = qdf_mc_timer_init(&adapter->tsf.host_capture_req_timer,
2086 				QDF_TIMER_TYPE_SW,
2087 				hdd_capture_req_timer_expired_handler,
2088 				(void *)adapter);
2089 	if (ret != QDF_STATUS_SUCCESS) {
2090 		hdd_err("Failed to init capture timer, ret: %d", ret);
2091 		qdf_mc_timer_destroy(&adapter->tsf.host_target_sync_timer);
2092 		goto fail;
2093 	}
2094 
2095 	hdd_tsf_regular_gpio_pulse_init(adapter);
2096 
2097 	net_dev = adapter->dev;
2098 	if (net_dev && hdd_tsf_is_dbg_fs_set(hddctx))
2099 		device_create_file(&net_dev->dev, &dev_attr_tsf);
2100 	hdd_set_th_sync_status(adapter, true);
2101 
2102 	qtime = qdf_get_log_timestamp();
2103 	host_time = hdd_get_monotonic_host_time(hddctx);
2104 
2105 	qtime = qdf_log_timestamp_to_usecs(qtime);
2106 	do_div(host_time, NSEC_PER_USEC);
2107 
2108 	adapter->delta_qtime = (qtime - host_time) * NSEC_PER_USEC;
2109 
2110 	return HDD_TSF_OP_SUCC;
2111 fail:
2112 	hdd_set_th_sync_status(adapter, false);
2113 	return HDD_TSF_OP_FAIL;
2114 }
2115 
hdd_tsf_sync_deinit(struct hdd_adapter * adapter)2116 static enum hdd_tsf_op_result hdd_tsf_sync_deinit(struct hdd_adapter *adapter)
2117 {
2118 	QDF_STATUS ret;
2119 	struct hdd_context *hddctx;
2120 	struct net_device *net_dev;
2121 
2122 	if (!adapter)
2123 		return HDD_TSF_OP_FAIL;
2124 
2125 	if (!hdd_get_th_sync_status(adapter))
2126 		return HDD_TSF_OP_SUCC;
2127 
2128 	hdd_set_th_sync_status(adapter, false);
2129 
2130 	hdd_tsf_regular_gpio_pulse_deinit(adapter);
2131 
2132 	ret = qdf_mc_timer_destroy(&adapter->tsf.host_target_sync_timer);
2133 	if (ret != QDF_STATUS_SUCCESS)
2134 		hdd_err("Failed to destroy target timer, ret: %d", ret);
2135 
2136 	ret = qdf_mc_timer_destroy(&adapter->tsf.host_capture_req_timer);
2137 	if (ret != QDF_STATUS_SUCCESS)
2138 		hdd_err("Failed to destroy capture timer, ret: %d", ret);
2139 
2140 	hddctx = WLAN_HDD_GET_CTX(adapter);
2141 
2142 	/* reset the cap_tsf flag and gpio if needed */
2143 	if (hddctx && qdf_atomic_read(&hddctx->tsf.cap_tsf_flag) &&
2144 	    hddctx->tsf.cap_tsf_context == adapter) {
2145 		int reset_ret = hdd_tsf_reset_gpio(adapter);
2146 
2147 		if (reset_ret)
2148 			hdd_err("Failed to reset tsf gpio, ret:%d",
2149 				reset_ret);
2150 		hddctx->tsf.cap_tsf_context = NULL;
2151 		qdf_atomic_set(&hddctx->tsf.cap_tsf_flag, 0);
2152 	}
2153 
2154 	hdd_reset_timestamps(adapter);
2155 
2156 	net_dev = adapter->dev;
2157 	if (net_dev && hdd_tsf_is_dbg_fs_set(hddctx)) {
2158 		struct device *dev = &net_dev->dev;
2159 
2160 		device_remove_file(dev, &dev_attr_tsf);
2161 	}
2162 	return HDD_TSF_OP_SUCC;
2163 }
2164 
hdd_start_tsf_sync(struct hdd_adapter * adapter)2165 int hdd_start_tsf_sync(struct hdd_adapter *adapter)
2166 {
2167 	enum hdd_tsf_op_result ret;
2168 
2169 	if (!adapter)
2170 		return -EINVAL;
2171 
2172 	ret = hdd_tsf_sync_init(adapter);
2173 	if (ret != HDD_TSF_OP_SUCC)
2174 		return -EINVAL;
2175 
2176 	return (__hdd_start_tsf_sync(adapter) ==
2177 		HDD_TSF_OP_SUCC) ? 0 : -EINVAL;
2178 }
2179 
hdd_restart_tsf_sync_post_wlan_resume(struct hdd_adapter * adapter)2180 void hdd_restart_tsf_sync_post_wlan_resume(struct hdd_adapter *adapter)
2181 {
2182 	QDF_STATUS status;
2183 	qdf_mc_timer_t *sync_timer;
2184 
2185 	if (!hdd_get_th_sync_status(adapter)) {
2186 		hdd_err("Host TSF sync is not initialized!!");
2187 		return;
2188 	}
2189 
2190 	sync_timer = &adapter->tsf.host_target_sync_timer;
2191 	if (QDF_TIMER_STATE_RUNNING ==
2192 		qdf_mc_timer_get_current_state(sync_timer)) {
2193 		status = qdf_mc_timer_stop_sync(sync_timer);
2194 		if (status != QDF_STATUS_SUCCESS) {
2195 			hdd_err("Couldn't stop Host TSF sync running timer!!");
2196 			return;
2197 		}
2198 
2199 		adapter->tsf.host_target_sync_force = true;
2200 		status = qdf_mc_timer_start(sync_timer, 10);
2201 		if (status != QDF_STATUS_SUCCESS)
2202 			hdd_err("Host TSF sync timer restart failed");
2203 
2204 		hdd_debug("Host TSF sync timer restarted post wlan resume");
2205 	}
2206 }
2207 
hdd_stop_tsf_sync(struct hdd_adapter * adapter)2208 int hdd_stop_tsf_sync(struct hdd_adapter *adapter)
2209 {
2210 	enum hdd_tsf_op_result ret;
2211 
2212 	if (!adapter)
2213 		return -EINVAL;
2214 
2215 	ret = __hdd_stop_tsf_sync(adapter);
2216 	if (ret != HDD_TSF_OP_SUCC)
2217 		return -EINVAL;
2218 
2219 	ret = hdd_tsf_sync_deinit(adapter);
2220 	if (ret != HDD_TSF_OP_SUCC) {
2221 		hdd_err("Failed to deinit tsf sync, ret: %d", ret);
2222 		return -EINVAL;
2223 	}
2224 	return 0;
2225 }
2226 
__hdd_capture_tsf(struct hdd_adapter * adapter,uint32_t * buf,int len)2227 static inline int __hdd_capture_tsf(struct hdd_adapter *adapter,
2228 				    uint32_t *buf, int len)
2229 {
2230 	if (!adapter || !buf) {
2231 		hdd_err("invalid pointer");
2232 		return -EINVAL;
2233 	}
2234 
2235 	if (len != 1)
2236 		return -EINVAL;
2237 
2238 	buf[0] = TSF_DISABLED_BY_TSFPLUS;
2239 
2240 	return 0;
2241 }
2242 
2243 /**
2244  * hdd_handle_tsf_dynamic_start()
2245  * @adapter: Adapter pointer
2246  * @attr: TSF sync interval from NL interface
2247  *
2248  * This function enables TSF sync if capture mode is Dynamic set from ini
2249  *
2250  * Return: 0 for success or non-zero negative failure code
2251  */
hdd_handle_tsf_dynamic_start(struct hdd_adapter * adapter,struct nlattr * attr)2252 static int hdd_handle_tsf_dynamic_start(struct hdd_adapter *adapter,
2253 					struct nlattr *attr)
2254 {
2255 	struct hdd_context *hdd_ctx;
2256 	struct hdd_vdev_tsf *tsf;
2257 	uint32_t dynamic_tsf_sync_interval = 0;
2258 
2259 	if (!adapter)
2260 		return -EINVAL;
2261 
2262 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2263 	if (wlan_hdd_validate_context(hdd_ctx))
2264 		return -EINVAL;
2265 
2266 	if (attr)
2267 		dynamic_tsf_sync_interval = nla_get_u32(attr);
2268 
2269 	tsf = &adapter->tsf;
2270 
2271 	if (tsf->enable_dynamic_tsf_sync) {
2272 		if (dynamic_tsf_sync_interval ==
2273 		    tsf->dynamic_tsf_sync_interval) {
2274 			return -EALREADY;
2275 		}
2276 		tsf->dynamic_tsf_sync_interval =
2277 			 dynamic_tsf_sync_interval;
2278 		return 0;
2279 	}
2280 
2281 	tsf->dynamic_tsf_sync_interval = dynamic_tsf_sync_interval;
2282 	tsf->enable_dynamic_tsf_sync = true;
2283 	if (hdd_tsf_is_time_sync_enabled_cfg(hdd_ctx))
2284 		pld_set_tsf_sync_period(hdd_ctx->parent_dev,
2285 					dynamic_tsf_sync_interval);
2286 
2287 	return hdd_start_tsf_sync(adapter);
2288 }
2289 
2290 /**
2291  * hdd_handle_tsf_dynamic_stop()
2292  * @adapter: Adapter pointer
2293  *
2294  * This function disable TSF sync if capture mode is Dynamic set from ini
2295  *
2296  * Return: 0 for success or non-zero negative failure code
2297  */
hdd_handle_tsf_dynamic_stop(struct hdd_adapter * adapter)2298 static int hdd_handle_tsf_dynamic_stop(struct hdd_adapter *adapter)
2299 {
2300 	struct hdd_context *hdd_ctx;
2301 
2302 	if (!adapter)
2303 		return -EINVAL;
2304 
2305 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2306 	if (wlan_hdd_validate_context(hdd_ctx))
2307 		return -EINVAL;
2308 
2309 	if (!adapter->tsf.enable_dynamic_tsf_sync)
2310 		return -EALREADY;
2311 
2312 	adapter->tsf.enable_dynamic_tsf_sync = false;
2313 	adapter->tsf.dynamic_tsf_sync_interval = 0;
2314 	if (hdd_tsf_is_time_sync_enabled_cfg(hdd_ctx))
2315 		pld_reset_tsf_sync_period(hdd_ctx->parent_dev);
2316 
2317 	return hdd_stop_tsf_sync(adapter);
2318 }
2319 
2320 #if defined(WLAN_FEATURE_TSF_TIMER_SYNC)
__hdd_indicate_tsf(struct hdd_adapter * adapter,struct hdd_tsf_op_response * tsf_op_resp)2321 static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter,
2322 						 struct hdd_tsf_op_response
2323 								*tsf_op_resp)
2324 {
2325 	if (!adapter || !tsf_op_resp) {
2326 		hdd_err("invalid pointer");
2327 		return HDD_TSF_OP_FAIL;
2328 	}
2329 
2330 	memset(tsf_op_resp, 0, sizeof(*tsf_op_resp));
2331 	if (!hdd_tsf_is_initialized(adapter)) {
2332 		tsf_op_resp->status = TSF_NOT_READY;
2333 		return HDD_TSF_OP_SUCC;
2334 	}
2335 
2336 	tsf_op_resp->status = hdd_tsf_check_conn_state(adapter);
2337 	if (tsf_op_resp->status != TSF_RETURN)
2338 		return HDD_TSF_OP_SUCC;
2339 
2340 	if (adapter->tsf.last_target_time == 0) {
2341 		hdd_info("TSF value not received");
2342 		tsf_op_resp->status = TSF_NOT_RETURNED_BY_FW;
2343 		return HDD_TSF_OP_SUCC;
2344 	}
2345 
2346 	tsf_op_resp->time = adapter->tsf.last_target_time;
2347 	tsf_op_resp->soc_time = adapter->tsf.last_tsf_sync_soc_time;
2348 
2349 	return HDD_TSF_OP_SUCC;
2350 }
2351 
2352 #else
__hdd_indicate_tsf(struct hdd_adapter * adapter,struct hdd_tsf_op_response * tsf_op_resp)2353 static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter,
2354 						 struct hdd_tsf_op_response
2355 								*tsf_op_resp)
2356 {
2357 	if (!adapter || !tsf_op_resp) {
2358 		hdd_err("invalid pointer");
2359 		return HDD_TSF_OP_FAIL;
2360 	}
2361 
2362 	tsf_op_resp->status = TSF_DISABLED_BY_TSFPLUS;
2363 	tsf_op_resp->time = 0;
2364 	tsf_op_resp->soc_time = 0;
2365 
2366 	return HDD_TSF_OP_SUCC;
2367 }
2368 #endif
2369 
2370 #ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS
2371 #ifdef CONFIG_HL_SUPPORT
2372 static inline
hdd_netbuf_timestamp(qdf_nbuf_t netbuf,uint64_t target_time)2373 enum hdd_tsf_op_result hdd_netbuf_timestamp(qdf_nbuf_t netbuf,
2374 					    uint64_t target_time)
2375 {
2376 	struct hdd_adapter *adapter;
2377 	struct net_device *net_dev = netbuf->dev;
2378 
2379 	if (!net_dev)
2380 		return HDD_TSF_OP_FAIL;
2381 
2382 	adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
2383 	if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC &&
2384 	    hdd_get_th_sync_status(adapter)) {
2385 		uint64_t host_time;
2386 		int32_t ret = hdd_get_hosttime_from_targettime(adapter,
2387 				target_time, &host_time);
2388 		if (!ret) {
2389 			netbuf->tstamp = ns_to_ktime(host_time);
2390 			return HDD_TSF_OP_SUCC;
2391 		}
2392 	}
2393 
2394 	return HDD_TSF_OP_FAIL;
2395 }
2396 
2397 #else
2398 static inline
hdd_netbuf_timestamp(qdf_nbuf_t netbuf,uint64_t target_time)2399 enum hdd_tsf_op_result hdd_netbuf_timestamp(qdf_nbuf_t netbuf,
2400 					    uint64_t target_time)
2401 {
2402 	struct hdd_adapter *adapter;
2403 	struct net_device *net_dev = netbuf->dev;
2404 	struct skb_shared_hwtstamps hwtstamps;
2405 
2406 	if (!net_dev)
2407 		return HDD_TSF_OP_FAIL;
2408 
2409 	adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
2410 	if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC &&
2411 	    hdd_get_th_sync_status(adapter)) {
2412 		uint64_t tsf64_time = target_time;
2413 		uint64_t soc_time = 0;/*ns*/
2414 		int32_t ret = hdd_get_soctime_from_tsf64time(adapter,
2415 				tsf64_time, &soc_time);
2416 		if (!ret) {
2417 			/* Adjust delta_qtime to soc_time(Qtime), so that
2418 			 * System Monotonic time and Qtime are in sync.
2419 			 */
2420 			if (soc_time > (adapter->delta_qtime)) {
2421 				hwtstamps.hwtstamp =
2422 				soc_time - (adapter->delta_qtime);
2423 				*skb_hwtstamps(netbuf) = hwtstamps;
2424 				netbuf->tstamp = ktime_set(0, 0);
2425 				return HDD_TSF_OP_SUCC;
2426 			} else {
2427 				return HDD_TSF_OP_FAIL;
2428 			}
2429 		}
2430 	}
2431 
2432 	return HDD_TSF_OP_FAIL;
2433 }
2434 #endif
2435 
2436 /**
2437  * hdd_tx_timestamp() - time stamp TX netbuf
2438  * @status: TX status
2439  * @netbuf: pointer to a TX netbuf
2440  * @target_time: TX time for the netbuf
2441  *
2442  * This function  get corresponding host time from target time,
2443  * and time stamp the TX netbuf with this time
2444  *
2445  * Return: Describe the execute result of this routine
2446  */
hdd_tx_timestamp(enum htt_tx_status status,qdf_nbuf_t netbuf,uint64_t target_time)2447 static int hdd_tx_timestamp(enum htt_tx_status status,
2448 			    qdf_nbuf_t netbuf, uint64_t target_time)
2449 {
2450 	struct sock *sk = netbuf->sk;
2451 
2452 	if (!sk)
2453 		return -EINVAL;
2454 
2455 	if ((skb_shinfo(netbuf)->tx_flags & SKBTX_HW_TSTAMP) &&
2456 	    !(skb_shinfo(netbuf)->tx_flags & SKBTX_IN_PROGRESS)) {
2457 		struct sock_exterr_skb *serr;
2458 		qdf_nbuf_t new_netbuf;
2459 		int err;
2460 
2461 		if (hdd_netbuf_timestamp(netbuf, target_time) !=
2462 		    HDD_TSF_OP_SUCC)
2463 			return -EINVAL;
2464 
2465 		new_netbuf = qdf_nbuf_clone(netbuf);
2466 		if (!new_netbuf)
2467 			return -ENOMEM;
2468 
2469 		serr = SKB_EXT_ERR(new_netbuf);
2470 		memset(serr, 0, sizeof(*serr));
2471 
2472 		switch (status) {
2473 		case htt_tx_status_ok:
2474 			serr->ee.ee_errno = ENOMSG;
2475 			break;
2476 		case htt_tx_status_discard:
2477 			serr->ee.ee_errno = ENOBUFS;
2478 			break;
2479 		case htt_tx_status_no_ack:
2480 			serr->ee.ee_errno = EREMOTEIO;
2481 			break;
2482 		default:
2483 			serr->ee.ee_errno = ENOMSG;
2484 			break;
2485 		}
2486 
2487 		hdd_debug("packet status %d, sock ee_errno %d",
2488 			  status, serr->ee.ee_errno);
2489 
2490 		serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
2491 
2492 		err = sock_queue_err_skb(sk, new_netbuf);
2493 		if (err) {
2494 			qdf_nbuf_free(new_netbuf);
2495 			return err;
2496 		}
2497 
2498 		return 0;
2499 	}
2500 	return -EINVAL;
2501 }
2502 
hdd_rx_timestamp(qdf_nbuf_t netbuf,uint64_t target_time)2503 int hdd_rx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time)
2504 {
2505 	if (hdd_netbuf_timestamp(netbuf, target_time) ==
2506 		HDD_TSF_OP_SUCC)
2507 		return 0;
2508 
2509 	/* reset tstamp when failed */
2510 	netbuf->tstamp = ktime_set(0, 0);
2511 	return -EINVAL;
2512 }
2513 
wlan_hdd_tsf_plus_sock_ts_init(struct hdd_context * hdd_ctx)2514 static inline void wlan_hdd_tsf_plus_sock_ts_init(struct hdd_context *hdd_ctx)
2515 {
2516 	if (hdd_tsf_is_tx_set(hdd_ctx))
2517 		ol_register_timestamp_callback(hdd_tx_timestamp);
2518 }
2519 
wlan_hdd_tsf_plus_sock_ts_deinit(struct hdd_context * hdd_ctx)2520 static inline void wlan_hdd_tsf_plus_sock_ts_deinit(struct hdd_context *hdd_ctx)
2521 {
2522 	if (hdd_tsf_is_tx_set(hdd_ctx))
2523 		ol_deregister_timestamp_callback();
2524 }
2525 #else
wlan_hdd_tsf_plus_sock_ts_init(struct hdd_context * hdd_ctx)2526 static inline void wlan_hdd_tsf_plus_sock_ts_init(struct hdd_context *hdd_ctx)
2527 {
2528 }
2529 
wlan_hdd_tsf_plus_sock_ts_deinit(struct hdd_context * hdd_ctx)2530 static inline void wlan_hdd_tsf_plus_sock_ts_deinit(struct hdd_context *hdd_ctx)
2531 {
2532 }
2533 #endif /* WLAN_FEATURE_TSF_PLUS_SOCK_TS */
2534 
2535 #if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ)
2536 static inline
wlan_hdd_tsf_plus_init(struct hdd_context * hdd_ctx)2537 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2538 {
2539 
2540 	wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx);
2541 	return HDD_TSF_OP_SUCC;
2542 }
2543 
2544 static inline
wlan_hdd_tsf_plus_deinit(struct hdd_context * hdd_ctx)2545 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2546 {
2547 	wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx);
2548 	return HDD_TSF_OP_SUCC;
2549 }
2550 
2551 #elif defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
2552 static
wlan_hdd_tsf_plus_init(struct hdd_context * hdd_ctx)2553 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2554 {
2555 	int ret;
2556 	QDF_STATUS status;
2557 	uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID;
2558 
2559 	status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc,
2560 						      &tsf_sync_gpio_pin);
2561 	if (QDF_IS_STATUS_ERROR(status)) {
2562 		hdd_err("tsf gpio irq host pin error");
2563 		goto fail;
2564 	}
2565 
2566 	if (tsf_sync_gpio_pin == TSF_GPIO_PIN_INVALID) {
2567 		hdd_err("gpio host pin is invalid");
2568 		goto fail;
2569 	}
2570 
2571 	ret = gpio_request(tsf_sync_gpio_pin, "wlan_tsf");
2572 	if (ret) {
2573 		hdd_err("gpio host pin is invalid");
2574 		goto fail;
2575 	}
2576 
2577 	ret = gpio_direction_output(tsf_sync_gpio_pin, OUTPUT_LOW);
2578 	if (ret) {
2579 		hdd_err("gpio host pin is invalid");
2580 		goto fail_free_gpio;
2581 	}
2582 
2583 	wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx);
2584 
2585 	return HDD_TSF_OP_SUCC;
2586 
2587 fail_free_gpio:
2588 	gpio_free(tsf_sync_gpio_pin);
2589 fail:
2590 	return HDD_TSF_OP_FAIL;
2591 }
2592 
2593 static
wlan_hdd_tsf_plus_deinit(struct hdd_context * hdd_ctx)2594 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2595 {
2596 	QDF_STATUS status;
2597 	uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID;
2598 
2599 	status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc,
2600 						      &tsf_sync_gpio_pin);
2601 	if (QDF_IS_STATUS_ERROR(status))
2602 		return QDF_STATUS_E_INVAL;
2603 
2604 	if (tsf_sync_gpio_pin == TSF_GPIO_PIN_INVALID)
2605 		return QDF_STATUS_E_INVAL;
2606 
2607 	wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx);
2608 
2609 	gpio_free(tsf_sync_gpio_pin);
2610 	return HDD_TSF_OP_SUCC;
2611 }
2612 
2613 #elif defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ)
2614 static
wlan_hdd_tsf_plus_init(struct hdd_context * hdd_ctx)2615 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2616 {
2617 	int ret;
2618 	QDF_STATUS status;
2619 	uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID;
2620 
2621 	status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc,
2622 						     &tsf_irq_gpio_pin);
2623 	if (QDF_IS_STATUS_ERROR(status)) {
2624 		hdd_err("tsf gpio irq host pin error");
2625 		goto fail;
2626 	}
2627 
2628 	if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID) {
2629 		hdd_err("gpio host pin is invalid");
2630 		goto fail;
2631 	}
2632 
2633 	ret = gpio_request(tsf_irq_gpio_pin, "wlan_tsf");
2634 	if (ret) {
2635 		hdd_err("gpio host pin is invalid");
2636 		goto fail;
2637 	}
2638 
2639 	ret = gpio_direction_input(tsf_irq_gpio_pin);
2640 	if (ret) {
2641 		hdd_err("gpio host pin is invalid");
2642 		goto fail_free_gpio;
2643 	}
2644 
2645 	tsf_gpio_irq_num = gpio_to_irq(tsf_irq_gpio_pin);
2646 	if (tsf_gpio_irq_num < 0) {
2647 		hdd_err("fail to get irq: %d", tsf_gpio_irq_num);
2648 		goto fail_free_gpio;
2649 	}
2650 
2651 	ret = request_irq(tsf_gpio_irq_num, hdd_tsf_captured_irq_handler,
2652 			  IRQF_SHARED | IRQF_TRIGGER_RISING, "wlan_tsf",
2653 			  hdd_ctx);
2654 
2655 	if (ret) {
2656 		hdd_err("Failed to register irq handler: %d", ret);
2657 		goto fail_free_gpio;
2658 	}
2659 
2660 	wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx);
2661 
2662 	return HDD_TSF_OP_SUCC;
2663 
2664 fail_free_gpio:
2665 	gpio_free(tsf_irq_gpio_pin);
2666 fail:
2667 	tsf_gpio_irq_num = -1;
2668 	return HDD_TSF_OP_FAIL;
2669 }
2670 
2671 static
wlan_hdd_tsf_plus_deinit(struct hdd_context * hdd_ctx)2672 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2673 {
2674 	QDF_STATUS status;
2675 	uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID;
2676 
2677 	status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc,
2678 						     &tsf_irq_gpio_pin);
2679 	if (QDF_IS_STATUS_ERROR(status))
2680 		return QDF_STATUS_E_INVAL;
2681 
2682 	if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID)
2683 		return QDF_STATUS_E_INVAL;
2684 
2685 	wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx);
2686 
2687 	if (tsf_gpio_irq_num >= 0) {
2688 		free_irq(tsf_gpio_irq_num, hdd_ctx);
2689 		tsf_gpio_irq_num = -1;
2690 		gpio_free(tsf_irq_gpio_pin);
2691 	}
2692 
2693 	return HDD_TSF_OP_SUCC;
2694 }
2695 
2696 #elif defined(WLAN_FEATURE_TSF_TIMER_SYNC)
2697 static inline
wlan_hdd_tsf_plus_init(struct hdd_context * hdd_ctx)2698 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2699 {
2700 	return HDD_TSF_OP_SUCC;
2701 }
2702 
2703 static inline
wlan_hdd_tsf_plus_deinit(struct hdd_context * hdd_ctx)2704 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2705 {
2706 	return HDD_TSF_OP_SUCC;
2707 }
2708 #else
2709 static inline
wlan_hdd_tsf_plus_init(struct hdd_context * hdd_ctx)2710 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2711 {
2712 	int ret;
2713 
2714 	ret = cnss_common_register_tsf_captured_handler(
2715 			hdd_ctx->parent_dev,
2716 			hdd_tsf_captured_irq_handler,
2717 			(void *)hdd_ctx);
2718 	if (ret != 0) {
2719 		hdd_err("Failed to register irq handler: %d", ret);
2720 		return HDD_TSF_OP_FAIL;
2721 	}
2722 
2723 	wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx);
2724 	return HDD_TSF_OP_SUCC;
2725 }
2726 
2727 static inline
wlan_hdd_tsf_plus_deinit(struct hdd_context * hdd_ctx)2728 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2729 {
2730 	int ret;
2731 
2732 	wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx);
2733 
2734 	ret = cnss_common_unregister_tsf_captured_handler(
2735 				hdd_ctx->parent_dev,
2736 				(void *)hdd_ctx);
2737 	if (ret != 0) {
2738 		hdd_err("Failed to unregister irq handler, ret:%d",
2739 			ret);
2740 		ret = HDD_TSF_OP_FAIL;
2741 	}
2742 
2743 	return HDD_TSF_OP_SUCC;
2744 }
2745 #endif
2746 #else
hdd_update_tsf(struct hdd_adapter * adapter,uint64_t tsf)2747 static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
2748 {
2749 }
2750 
__hdd_indicate_tsf(struct hdd_adapter * adapter,struct hdd_tsf_op_response * tsf_op_resp)2751 static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter,
2752 						 struct hdd_tsf_op_response
2753 								*tsf_op_resp)
2754 {
2755 	return hdd_indicate_tsf_internal(adapter, tsf_op_resp);
2756 }
2757 
__hdd_capture_tsf(struct hdd_adapter * adapter,uint32_t * buf,int len)2758 static inline int __hdd_capture_tsf(struct hdd_adapter *adapter,
2759 				    uint32_t *buf, int len)
2760 {
2761 	return (hdd_capture_tsf_internal(adapter, buf, len) ==
2762 		HDD_TSF_OP_SUCC) ? 0 : -EINVAL;
2763 }
2764 
2765 static inline
wlan_hdd_tsf_plus_init(struct hdd_context * hdd_ctx)2766 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
2767 {
2768 	return HDD_TSF_OP_SUCC;
2769 }
2770 
2771 static inline
wlan_hdd_tsf_plus_deinit(struct hdd_context * hdd_ctx)2772 enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
2773 {
2774 	return HDD_TSF_OP_SUCC;
2775 }
2776 
hdd_handle_tsf_dynamic_start(struct hdd_adapter * adapter,struct nlattr * attr)2777 static inline int hdd_handle_tsf_dynamic_start(struct hdd_adapter *adapter,
2778 					       struct nlattr *attr)
2779 {
2780 	return -ENOTSUPP;
2781 }
2782 
hdd_handle_tsf_dynamic_stop(struct hdd_adapter * adapter)2783 static inline int hdd_handle_tsf_dynamic_stop(struct hdd_adapter *adapter)
2784 {
2785 	return -ENOTSUPP;
2786 }
2787 #endif /* WLAN_FEATURE_TSF_PLUS */
2788 
hdd_capture_tsf(struct hdd_adapter * adapter,uint32_t * buf,int len)2789 int hdd_capture_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len)
2790 {
2791 	return __hdd_capture_tsf(adapter, buf, len);
2792 }
2793 
hdd_indicate_tsf(struct hdd_adapter * adapter,struct hdd_tsf_op_response * tsf_op_resp)2794 int hdd_indicate_tsf(struct hdd_adapter *adapter,
2795 		     struct hdd_tsf_op_response *tsf_op_resp)
2796 {
2797 	if (__hdd_indicate_tsf(adapter, tsf_op_resp) == HDD_TSF_OP_FAIL)
2798 		return -EINVAL;
2799 
2800 	switch (tsf_op_resp->status) {
2801 	case TSF_RETURN:
2802 		return 0;
2803 	case TSF_NOT_RETURNED_BY_FW:
2804 		return -EINPROGRESS;
2805 	case TSF_STA_NOT_CONNECTED_NO_TSF:
2806 	case TSF_SAP_NOT_STARTED_NO_TSF:
2807 		return -EPERM;
2808 	default:
2809 		return -EINVAL;
2810 	}
2811 }
2812 
2813 #ifdef WLAN_FEATURE_TSF_PTP
wlan_get_ts_info(struct net_device * dev,struct ethtool_ts_info * info)2814 int wlan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
2815 
2816 {
2817 	struct hdd_adapter *adapter = netdev_priv(dev);
2818 	struct osif_vdev_sync *vdev_sync;
2819 	struct hdd_context *hdd_ctx;
2820 	int errno;
2821 
2822 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2823 	errno = wlan_hdd_validate_context(hdd_ctx);
2824 	if (errno)
2825 		return -EINVAL;
2826 
2827 	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
2828 	if (errno)
2829 		return -EAGAIN;
2830 
2831 	info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
2832 				 SOF_TIMESTAMPING_RX_HARDWARE |
2833 				 SOF_TIMESTAMPING_RAW_HARDWARE;
2834 	if (hdd_ctx->tsf.ptp_clock)
2835 		info->phc_index = ptp_clock_index(hdd_ctx->tsf.ptp_clock);
2836 	else
2837 		info->phc_index = -1;
2838 
2839 	osif_vdev_sync_op_stop(vdev_sync);
2840 	return 0;
2841 }
2842 
2843 #if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE)
2844 /**
2845  * wlan_ptp_gettime() - return fw ts info to uplayer
2846  * @ptp: pointer to ptp_clock_info.
2847  * @ts: pointer to timespec.
2848  *
2849  * Return: Describe the execute result of this routine
2850  */
wlan_ptp_gettime(struct ptp_clock_info * ptp,struct timespec * ts)2851 static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
2852 {
2853 	uint64_t host_time, target_time = 0;
2854 	struct hdd_context *hdd_ctx;
2855 	struct hdd_adapter *adapter;
2856 	struct osif_psoc_sync *psoc_sync;
2857 	int errno, status = 0;
2858 
2859 	hdd_ctx = = cds_get_context(QDF_MODULE_ID_HDD);
2860 	errno = wlan_hdd_validate_context(hdd_ctx);
2861 	if (errno)
2862 		return -EINVAL;
2863 
2864 	errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync);
2865 	if (errno)
2866 		return -EAGAIN;
2867 
2868 	adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE);
2869 	if (!adapter) {
2870 		adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE);
2871 		if (!adapter) {
2872 			adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
2873 			if (!adapter)
2874 				adapter = hdd_get_adapter(hdd_ctx,
2875 							  QDF_STA_MODE);
2876 				if (!adapter) {
2877 					status = -EOPNOTSUPP;
2878 					goto end;
2879 				}
2880 		}
2881 	}
2882 
2883 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
2884 	if (hdd_get_targettime_from_hosttime(adapter, host_time,
2885 					     &target_time)) {
2886 		hdd_err("get invalid target timestamp");
2887 		status = -EINVAL;
2888 		goto end;
2889 	}
2890 	*ts = ns_to_timespec(target_time * NSEC_PER_USEC);
2891 
2892 end:
2893 	osif_psoc_sync_op_stop(psoc_sync);
2894 	return status;
2895 }
2896 
2897 /**
2898  * wlan_hdd_phc_init() - phc init
2899  * @hdd_ctx: pointer to the hdd_context.
2900  *
2901  * Return: NULL
2902  */
wlan_hdd_phc_init(struct hdd_context * hdd_ctx)2903 static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
2904 {
2905 	hdd_ctx->tsf.ptp_cinfo.gettime = wlan_ptp_gettime;
2906 
2907 	hdd_ctx->tsf.ptp_clock = ptp_clock_register(&hdd_ctx->tsf.ptp_cinfo,
2908 						    hdd_ctx->parent_dev);
2909 }
2910 
2911 /**
2912  * wlan_hdd_phc_deinit() - phc deinit
2913  * @hdd_ctx: pointer to the hdd_context.
2914  *
2915  * Return: NULL
2916  */
wlan_hdd_phc_deinit(struct hdd_context * hdd_ctx)2917 static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
2918 {
2919 	hdd_ctx->tsf.ptp_cinfo.gettime = NULL;
2920 
2921 	if (hdd_ctx->tsf.ptp_clock) {
2922 		ptp_clock_unregister(hdd_ctx->tsf.ptp_clock);
2923 		hdd_ctx->tsf.ptp_clock = NULL;
2924 	}
2925 }
2926 
2927 #else
wlan_ptp_gettime(struct ptp_clock_info * ptp,struct timespec64 * ts)2928 static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
2929 {
2930 	uint64_t host_time, target_time = 0;
2931 	struct hdd_context *hdd_ctx;
2932 	struct hdd_adapter *adapter;
2933 	struct osif_psoc_sync *psoc_sync;
2934 	int errno, status = 0;
2935 
2936 	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
2937 	errno = wlan_hdd_validate_context(hdd_ctx);
2938 	if (errno)
2939 		return -EINVAL;
2940 
2941 	errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync);
2942 	if (errno)
2943 		return -EAGAIN;
2944 
2945 	adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE);
2946 	if (!adapter) {
2947 		adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE);
2948 		if (!adapter) {
2949 			adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
2950 			if (!adapter)
2951 				adapter = hdd_get_adapter(hdd_ctx,
2952 							  QDF_STA_MODE);
2953 				if (!adapter) {
2954 					status = -EOPNOTSUPP;
2955 					goto end;
2956 				}
2957 		}
2958 	}
2959 
2960 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
2961 	if (hdd_get_targettime_from_hosttime(adapter, host_time,
2962 					     &target_time)) {
2963 		hdd_err("get invalid target timestamp");
2964 		status = -EINVAL;
2965 		goto end;
2966 	}
2967 	*ts = ns_to_timespec64(target_time * NSEC_PER_USEC);
2968 
2969 end:
2970 	osif_psoc_sync_op_stop(psoc_sync);
2971 	return status;
2972 }
2973 
wlan_hdd_phc_init(struct hdd_context * hdd_ctx)2974 static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
2975 {
2976 	hdd_ctx->tsf.ptp_cinfo.gettime64 = wlan_ptp_gettime;
2977 	hdd_ctx->tsf.ptp_clock = ptp_clock_register(&hdd_ctx->tsf.ptp_cinfo,
2978 						    hdd_ctx->parent_dev);
2979 }
2980 
wlan_hdd_phc_deinit(struct hdd_context * hdd_ctx)2981 static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
2982 {
2983 	hdd_ctx->tsf.ptp_cinfo.gettime64 = NULL;
2984 
2985 	if (hdd_ctx->tsf.ptp_clock) {
2986 		ptp_clock_unregister(hdd_ctx->tsf.ptp_clock);
2987 		hdd_ctx->tsf.ptp_clock = NULL;
2988 	}
2989 }
2990 
2991 #endif
2992 #else
2993 
wlan_hdd_phc_init(struct hdd_context * hdd_ctx)2994 static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
2995 {
2996 }
2997 
wlan_hdd_phc_deinit(struct hdd_context * hdd_ctx)2998 static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
2999 {
3000 }
3001 #endif /* WLAN_FEATURE_TSF_PTP */
3002 
3003 #ifdef WLAN_FEATURE_TSF_AUTO_REPORT
hdd_tsf_auto_report_init(struct hdd_adapter * adapter)3004 void hdd_tsf_auto_report_init(struct hdd_adapter *adapter)
3005 {
3006 	adapter->tsf.auto_rpt_src = 0;
3007 }
3008 
3009 int
hdd_set_tsf_auto_report(struct hdd_adapter * adapter,bool ena,enum hdd_tsf_auto_rpt_source source)3010 hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena,
3011 			enum hdd_tsf_auto_rpt_source source)
3012 {
3013 	int ret = 0;
3014 	bool enabled;
3015 
3016 	enabled = !!adapter->tsf.auto_rpt_src;
3017 	if (enabled == ena) {
3018 		hdd_debug_rl("source %d current %d and no action is required",
3019 			     source, enabled);
3020 		goto set_src;
3021 	}
3022 
3023 	ret = wma_cli_set_command((int)adapter->deflink->vdev_id,
3024 				  ena ? (int)GEN_PARAM_TSF_AUTO_REPORT_ENABLE :
3025 				  (int)GEN_PARAM_TSF_AUTO_REPORT_DISABLE,
3026 				  ena, GEN_CMD);
3027 	if (ret) {
3028 		hdd_err_rl("source %d enable %d failed: %d", source, ena, ret);
3029 		ret = -EINPROGRESS;
3030 		goto out;
3031 	}
3032 
3033 set_src:
3034 	if (ena)
3035 		qdf_atomic_set_bit(source, &adapter->tsf.auto_rpt_src);
3036 	else
3037 		qdf_atomic_clear_bit(source, &adapter->tsf.auto_rpt_src);
3038 
3039 out:
3040 	return ret;
3041 }
3042 
3043 /**
3044  * hdd_tsf_auto_report_enabled() - get current state of tsf auto report
3045  * for an adapter
3046  * @adapter: pointer to Adapter context
3047  *
3048  * Return: true for enabled, false for disabled
3049  */
hdd_tsf_auto_report_enabled(struct hdd_adapter * adapter)3050 static inline bool hdd_tsf_auto_report_enabled(struct hdd_adapter *adapter)
3051 {
3052 	return !!adapter->tsf.auto_rpt_src;
3053 }
3054 
3055 /**
3056  * hdd_set_delta_tsf() - calculate and save the time difference between
3057  * TQM clock and TSF clock
3058  * @adapter: pointer to Adapter context
3059  * @ptsf: pointer to tsf information
3060  *
3061  * Return: QDF_STATUS
3062  */
hdd_set_delta_tsf(struct hdd_adapter * adapter,struct stsf * ptsf)3063 static QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter,
3064 				    struct stsf *ptsf)
3065 {
3066 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
3067 	uint32_t delta_tsf;
3068 
3069 	/* A tsf report event with mac_id_valid equals to 1 represents
3070 	 * for tsf auto report, that's what we need to handle in this
3071 	 * function; otherwise, return failure here so that legacy BSS
3072 	 * TSF logic can be continued.
3073 	 */
3074 	if (!ptsf->mac_id_valid) {
3075 		hdd_debug_rl("Not TSF auto report");
3076 		return QDF_STATUS_E_FAILURE;
3077 	}
3078 
3079 	if (!hdd_tsf_auto_report_enabled(adapter)) {
3080 		hdd_debug_rl("adapter %u tsf_auto_report disabled",
3081 			     adapter->deflink->vdev_id);
3082 		goto exit_with_success;
3083 	}
3084 
3085 	delta_tsf = ptsf->tsf_low - ptsf->soc_timer_low;
3086 	hdd_debug("vdev %u tsf_low %u qtimer_low %u delta_tsf %u",
3087 		  ptsf->vdev_id, ptsf->tsf_low, ptsf->soc_timer_low, delta_tsf);
3088 
3089 	/* Pass delta_tsf to DP layer to calculate hw delay
3090 	 * on a per vdev basis
3091 	 */
3092 	cdp_set_delta_tsf(soc, adapter->deflink->vdev_id, delta_tsf);
3093 
3094 exit_with_success:
3095 	return QDF_STATUS_SUCCESS;
3096 }
3097 #else /* !WLAN_FEATURE_TSF_AUTO_REPORT */
hdd_set_delta_tsf(struct hdd_adapter * adapter,struct stsf * ptsf)3098 static inline QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter,
3099 					   struct stsf *ptsf)
3100 {
3101 	return QDF_STATUS_E_NOSUPPORT;
3102 }
3103 
hdd_tsf_auto_report_enabled(struct hdd_adapter * adapter)3104 static inline bool hdd_tsf_auto_report_enabled(struct hdd_adapter *adapter)
3105 {
3106 	return false;
3107 }
3108 #endif /* WLAN_FEATURE_TSF_AUTO_REPORT */
3109 
3110 #ifdef WLAN_FEATURE_TSF_UPLINK_DELAY
3111 /**
3112  * hdd_set_tsf_ul_delay_report() - enable or disable tsf uplink delay report
3113  * for an adapter
3114  * @adapter: pointer to Adapter context
3115  * @ena: requesting state (true or false)
3116  *
3117  * Return: 0 for success or non-zero negative failure code
3118  */
3119 static int
hdd_set_tsf_ul_delay_report(struct hdd_adapter * adapter,bool ena)3120 hdd_set_tsf_ul_delay_report(struct hdd_adapter *adapter, bool ena)
3121 {
3122 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
3123 	QDF_STATUS status;
3124 
3125 	status = cdp_set_tsf_ul_delay_report(soc,
3126 					     adapter->deflink->vdev_id,
3127 					     ena);
3128 
3129 	if (QDF_IS_STATUS_ERROR(status)) {
3130 		hdd_err_rl("Set tsf report uplink delay failed");
3131 		return -EPERM;
3132 	}
3133 
3134 	return 0;
3135 }
3136 
hdd_get_uplink_delay_len(struct hdd_adapter * adapter)3137 uint32_t hdd_get_uplink_delay_len(struct hdd_adapter *adapter)
3138 {
3139 	if (adapter->device_mode != QDF_STA_MODE)
3140 		return 0;
3141 
3142 	return nla_total_size(sizeof(uint32_t));
3143 }
3144 
hdd_add_uplink_delay(struct hdd_adapter * adapter,struct sk_buff * skb)3145 QDF_STATUS hdd_add_uplink_delay(struct hdd_adapter *adapter,
3146 				struct sk_buff *skb)
3147 {
3148 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
3149 	QDF_STATUS status;
3150 	uint32_t ul_delay;
3151 
3152 	if (adapter->device_mode != QDF_STA_MODE &&
3153 	    adapter->device_mode != QDF_P2P_CLIENT_MODE)
3154 		return QDF_STATUS_SUCCESS;
3155 
3156 	if (hdd_tsf_auto_report_enabled(adapter)) {
3157 		status = cdp_get_uplink_delay(soc, adapter->deflink->vdev_id,
3158 					      &ul_delay);
3159 		if (QDF_IS_STATUS_ERROR(status))
3160 			ul_delay = 0;
3161 	} else {
3162 		ul_delay = 0;
3163 	}
3164 
3165 	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY,
3166 			ul_delay))
3167 		return QDF_STATUS_E_FAILURE;
3168 
3169 	return QDF_STATUS_SUCCESS;
3170 }
3171 #else
3172 static inline int
hdd_set_tsf_ul_delay_report(struct hdd_adapter * adapter,bool ena)3173 hdd_set_tsf_ul_delay_report(struct hdd_adapter *adapter, bool ena)
3174 {
3175 	return -ENOTSUPP;
3176 }
3177 #endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */
3178 
3179 /**
3180  * hdd_get_tsf_cb() - handle tsf callback
3181  * @pcb_cxt: pointer to the hdd_contex
3182  * @ptsf: pointer to struct stsf
3183  *
3184  * This function handle the event that reported by firmware at first.
3185  * The event contains the vdev_id, current tsf value of this vdev,
3186  * tsf value is 64bits, discripted in two variable tsf_low and tsf_high.
3187  * These two values each is uint32.
3188  *
3189  * Return: 0 for success or non-zero negative failure code
3190  */
hdd_get_tsf_cb(void * pcb_cxt,struct stsf * ptsf)3191 int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf)
3192 {
3193 	struct hdd_context *hddctx;
3194 	struct hdd_adapter *adapter;
3195 	struct wlan_hdd_link_info *link_info;
3196 	int ret;
3197 	uint64_t tsf_sync_soc_time;
3198 	QDF_TIMER_STATE capture_req_timer_status;
3199 	qdf_mc_timer_t *capture_timer;
3200 	struct hdd_vdev_tsf *tsf;
3201 
3202 	if (!pcb_cxt || !ptsf) {
3203 		hdd_err("HDD context is not valid");
3204 			return -EINVAL;
3205 	}
3206 
3207 	hddctx = (struct hdd_context *)pcb_cxt;
3208 	ret = wlan_hdd_validate_context(hddctx);
3209 	if (0 != ret)
3210 		return -EINVAL;
3211 
3212 	link_info = hdd_get_link_info_by_vdev(hddctx, ptsf->vdev_id);
3213 	if (!link_info) {
3214 		hdd_err("failed to find adapter");
3215 		return -EINVAL;
3216 	}
3217 
3218 	adapter = link_info->adapter;
3219 	/* Intercept tsf report and check if it is for auto report.
3220 	 * If yes, return in advance and skip the legacy BSS TSF
3221 	 * report. Otherwise continue on to the legacy BSS TSF
3222 	 * report logic.
3223 	 */
3224 	if (QDF_IS_STATUS_SUCCESS(hdd_set_delta_tsf(adapter, ptsf)))
3225 		return 0;
3226 
3227 	if (!hdd_tsf_is_initialized(adapter)) {
3228 		hdd_err("tsf is not init, ignore tsf event");
3229 		return -EINVAL;
3230 	}
3231 
3232 	hdd_debug("tsf cb handle event, device_mode is %d",
3233 		  adapter->device_mode);
3234 
3235 	wlan_hdd_tsf_reg_update_details(adapter, ptsf);
3236 
3237 	tsf = &adapter->tsf;
3238 	capture_timer = &tsf->host_capture_req_timer;
3239 	capture_req_timer_status =
3240 		qdf_mc_timer_get_current_state(capture_timer);
3241 	if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) {
3242 		hdd_warn("invalid timer status");
3243 		return -EINVAL;
3244 	}
3245 
3246 	qdf_mc_timer_stop(capture_timer);
3247 	tsf->cur_target_time = ((uint64_t)ptsf->tsf_high << 32 |
3248 			 ptsf->tsf_low);
3249 
3250 	tsf->cur_target_global_tsf_time =
3251 		((uint64_t)ptsf->global_tsf_high << 32 |
3252 			 ptsf->global_tsf_low);
3253 	tsf_sync_soc_time = ((uint64_t)ptsf->soc_timer_high << 32 |
3254 			ptsf->soc_timer_low);
3255 	tsf->cur_tsf_sync_soc_time =
3256 		hdd_convert_qtime_to_us(tsf_sync_soc_time) * NSEC_PER_USEC;
3257 
3258 	qdf_event_set(&tsf_sync_get_completion_evt);
3259 	hdd_update_tsf(adapter, tsf->cur_target_time);
3260 	hdd_debug("Vdev=%u, tsf_low=%u, tsf_high=%u ptsf->soc_timer_low=%u ptsf->soc_timer_high=%u",
3261 		  ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high,
3262 		  ptsf->soc_timer_low, ptsf->soc_timer_high);
3263 	return 0;
3264 }
3265 
3266 const struct nla_policy tsf_policy[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1] = {
3267 	[QCA_WLAN_VENDOR_ATTR_TSF_CMD] = {.type = NLA_U32},
3268 	[QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL] = {.type = NLA_U32},
3269 };
3270 
3271 /**
3272  * __wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations
3273  * @wiphy: Pointer to wireless phy
3274  * @wdev: Pointer to wireless device
3275  * @data: Pointer to data
3276  * @data_len: Data length
3277  *
3278  * Handle TSF SET / GET operation from userspace
3279  *
3280  * Return: 0 on success, negative errno on failure
3281  */
__wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3282 static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
3283 					struct wireless_dev *wdev,
3284 					const void *data,
3285 					int data_len)
3286 {
3287 	struct net_device *dev = wdev->netdev;
3288 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3289 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
3290 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1];
3291 	struct hdd_tsf_op_response tsf_op_resp;
3292 	struct nlattr *attr;
3293 	enum hdd_tsf_get_state value;
3294 	int status;
3295 	QDF_STATUS ret;
3296 	struct sk_buff *reply_skb;
3297 	uint32_t tsf_cmd;
3298 	enum qca_nl80211_vendor_subcmds_index index =
3299 		QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX;
3300 	bool enable_auto_rpt;
3301 	enum hdd_tsf_auto_rpt_source source =
3302 		HDD_TSF_AUTO_RPT_SOURCE_UPLINK_DELAY;
3303 
3304 	hdd_enter_dev(wdev->netdev);
3305 
3306 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
3307 		hdd_err("Command not allowed in FTM mode");
3308 		return -EPERM;
3309 	}
3310 
3311 	status = wlan_hdd_validate_context(hdd_ctx);
3312 	if (0 != status)
3313 		return -EINVAL;
3314 
3315 	if (wlan_cfg80211_nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TSF_MAX,
3316 				    data, data_len, tsf_policy)) {
3317 		hdd_err("Invalid TSF cmd");
3318 		return -EINVAL;
3319 	}
3320 
3321 	if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]) {
3322 		hdd_err("Invalid TSF cmd");
3323 		return -EINVAL;
3324 	}
3325 	tsf_cmd = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]);
3326 
3327 	/* Intercept tsf_cmd for TSF auto report enable or disable subcmds,
3328 	 * and treat as trigger for uplink delay report.
3329 	 */
3330 	if (tsf_cmd == QCA_TSF_AUTO_REPORT_DISABLE ||
3331 	    tsf_cmd == QCA_TSF_AUTO_REPORT_ENABLE) {
3332 		enable_auto_rpt = (tsf_cmd == QCA_TSF_AUTO_REPORT_ENABLE);
3333 		status = hdd_set_tsf_auto_report(adapter,
3334 						 enable_auto_rpt,
3335 						 source);
3336 		if (status)
3337 			goto end;
3338 
3339 		hdd_set_tsf_ul_delay_report(adapter, enable_auto_rpt);
3340 		goto end;
3341 	}
3342 
3343 	ret = qdf_event_reset(&tsf_sync_get_completion_evt);
3344 	if (QDF_IS_STATUS_ERROR(ret))
3345 		hdd_warn("failed to reset tsf_sync_get_completion_evt");
3346 
3347 	if (tsf_cmd == QCA_TSF_CAPTURE || tsf_cmd == QCA_TSF_SYNC_GET) {
3348 		hdd_capture_tsf(adapter, &value, 1);
3349 		switch (value) {
3350 		case TSF_RETURN:
3351 			status = 0;
3352 			break;
3353 		case TSF_CURRENT_IN_CAP_STATE:
3354 			status = -EALREADY;
3355 			break;
3356 		case TSF_STA_NOT_CONNECTED_NO_TSF:
3357 		case TSF_SAP_NOT_STARTED_NO_TSF:
3358 			status = -EPERM;
3359 			break;
3360 		default:
3361 		case TSF_CAPTURE_FAIL:
3362 			status = -EINVAL;
3363 			break;
3364 		}
3365 	} else if (tsf_cmd == QCA_TSF_SYNC_START) {
3366 		attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL];
3367 		status = hdd_handle_tsf_dynamic_start(adapter, attr);
3368 	} else if (tsf_cmd == QCA_TSF_SYNC_STOP) {
3369 		status = hdd_handle_tsf_dynamic_stop(adapter);
3370 	} else {
3371 		status = 0;
3372 	}
3373 
3374 	if (status < 0)
3375 		goto end;
3376 
3377 	if (tsf_cmd == QCA_TSF_SYNC_GET) {
3378 		ret = qdf_wait_single_event(&tsf_sync_get_completion_evt,
3379 					    WLAN_TSF_SYNC_GET_TIMEOUT);
3380 		if (QDF_IS_STATUS_ERROR(ret)) {
3381 			status = -ETIMEDOUT;
3382 			goto end;
3383 		}
3384 	}
3385 
3386 	if (tsf_cmd == QCA_TSF_GET || tsf_cmd == QCA_TSF_SYNC_GET) {
3387 		status = hdd_indicate_tsf(adapter, &tsf_op_resp);
3388 		if (status != 0)
3389 			goto end;
3390 
3391 		reply_skb =
3392 			wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
3393 							 sizeof(uint64_t) * 2 +
3394 							 NLMSG_HDRLEN,
3395 							 index, GFP_KERNEL);
3396 		if (!reply_skb) {
3397 			hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
3398 			status = -ENOMEM;
3399 			goto end;
3400 		}
3401 		if (hdd_wlan_nla_put_u64(reply_skb,
3402 				QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE,
3403 				tsf_op_resp.time) ||
3404 		    hdd_wlan_nla_put_u64(reply_skb,
3405 				QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE,
3406 				tsf_op_resp.soc_time)) {
3407 			hdd_err("nla put fail");
3408 			wlan_cfg80211_vendor_free_skb(reply_skb);
3409 			status = -EINVAL;
3410 			goto end;
3411 		}
3412 		status = wlan_cfg80211_vendor_cmd_reply(reply_skb);
3413 	}
3414 
3415 end:
3416 	hdd_info("TSF operation %d status: %d", tsf_cmd, status);
3417 	return status;
3418 }
3419 
wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3420 int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
3421 					struct wireless_dev *wdev,
3422 					const void *data,
3423 					int data_len)
3424 {
3425 	int errno;
3426 	struct osif_vdev_sync *vdev_sync;
3427 
3428 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
3429 	if (errno)
3430 		return errno;
3431 
3432 	errno = __wlan_hdd_cfg80211_handle_tsf_cmd(wiphy, wdev, data, data_len);
3433 
3434 	osif_vdev_sync_op_stop(vdev_sync);
3435 
3436 	return errno;
3437 }
3438 
3439 /**
3440  * wlan_hdd_tsf_init() - set callback to handle tsf value.
3441  * @hdd_ctx: pointer to the struct hdd_context
3442  *
3443  * This function set the callback to sme module, the callback will be
3444  * called when a tsf event is reported by firmware
3445  *
3446  * Return: none
3447  */
wlan_hdd_tsf_init(struct hdd_context * hdd_ctx)3448 void wlan_hdd_tsf_init(struct hdd_context *hdd_ctx)
3449 {
3450 	QDF_STATUS status;
3451 
3452 	if (!hdd_ctx)
3453 		return;
3454 
3455 	if (qdf_atomic_inc_return(&hdd_ctx->tsf.tsf_ready_flag) > 1) {
3456 		hdd_err("TSF ready flag already set");
3457 		return;
3458 	}
3459 
3460 	qdf_atomic_init(&hdd_ctx->tsf.cap_tsf_flag);
3461 
3462 	status = qdf_event_create(&tsf_sync_get_completion_evt);
3463 	if (QDF_IS_STATUS_ERROR(status)) {
3464 		hdd_err("failed to create tsf_sync_get_completion_evt");
3465 		goto fail;
3466 	}
3467 
3468 	status = hdd_tsf_set_gpio(hdd_ctx);
3469 
3470 	if (QDF_STATUS_SUCCESS != status) {
3471 		hdd_err("set tsf GPIO failed, status: %d", status);
3472 		goto fail;
3473 	}
3474 
3475 	if (wlan_hdd_tsf_plus_init(hdd_ctx) != HDD_TSF_OP_SUCC) {
3476 		hdd_err("TSF plus init  failed");
3477 		goto fail;
3478 	}
3479 
3480 	if (hdd_tsf_is_ptp_enabled(hdd_ctx))
3481 		wlan_hdd_phc_init(hdd_ctx);
3482 
3483 	return;
3484 
3485 fail:
3486 	qdf_atomic_set(&hdd_ctx->tsf.tsf_ready_flag, 0);
3487 }
3488 
wlan_hdd_tsf_deinit(struct hdd_context * hdd_ctx)3489 void wlan_hdd_tsf_deinit(struct hdd_context *hdd_ctx)
3490 {
3491 	QDF_STATUS status;
3492 
3493 	if (!hdd_ctx)
3494 		return;
3495 
3496 	status = qdf_event_destroy(&tsf_sync_get_completion_evt);
3497 	if (QDF_IS_STATUS_ERROR(status))
3498 		hdd_err("failed to destroy tsf_sync_get_completion_evt");
3499 
3500 	if (!qdf_atomic_read(&hdd_ctx->tsf.tsf_ready_flag)) {
3501 		hdd_err("ready flag not set");
3502 		return;
3503 	}
3504 
3505 	if (hdd_tsf_is_ptp_enabled(hdd_ctx))
3506 		wlan_hdd_phc_deinit(hdd_ctx);
3507 	wlan_hdd_tsf_plus_deinit(hdd_ctx);
3508 	qdf_atomic_set(&hdd_ctx->tsf.tsf_ready_flag, 0);
3509 	qdf_atomic_set(&hdd_ctx->tsf.cap_tsf_flag, 0);
3510 }
3511