blob: f4116f333660f33f12aee076fbb6847120fd23aa [file] [log] [blame]
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07001/*
Manikandan Mohan0faf6282019-01-14 18:00:04 -08002 * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07003 *
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
Manikandan Mohandcc21ba2016-03-15 14:31:56 -070019/**
20 * wlan_hdd_tsf.c - WLAN Host Device Driver tsf related implementation
21 */
22
Dustin Browna09acf42018-11-08 12:32:26 +053023#include "osif_sync.h"
Manikandan Mohandcc21ba2016-03-15 14:31:56 -070024#include "wlan_hdd_main.h"
Jeff Johnsondde34492016-10-05 16:28:04 -070025#include "wlan_hdd_tsf.h"
Manikandan Mohandcc21ba2016-03-15 14:31:56 -070026#include "wma_api.h"
Sourav Mohapatra0f3b8572018-09-12 10:03:51 +053027#include "wlan_fwol_ucfg_api.h"
Sandeep Puligillafdd201e2017-02-02 18:43:46 -080028#include <qca_vendor.h>
yuanl2746f072018-09-21 19:19:16 +080029#include <linux/errqueue.h>
Subrat Dashb1e61b22019-07-22 14:09:34 +053030#if defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ) || \
31 defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
Subrat Dash5f36fbe2019-02-12 16:28:14 +053032#include <linux/gpio.h>
Subrat Dash5f36fbe2019-02-12 16:28:14 +053033#endif
Subrat Dashb1e61b22019-07-22 14:09:34 +053034
yuanl2746f072018-09-21 19:19:16 +080035#include "ol_txrx_api.h"
Dustin Browna09acf42018-11-08 12:32:26 +053036
Subrat Dashb1e61b22019-07-22 14:09:34 +053037#ifdef WLAN_FEATURE_TSF_PLUS
38#ifndef WLAN_FEATURE_TSF_PLUS_NOIRQ
39#ifndef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC
40static int tsf_gpio_irq_num = -1;
41#endif
42#endif
43#endif
Manikandan Mohan5356c2b2016-04-03 15:51:35 -070044static struct completion tsf_sync_get_completion_evt;
45#define WLAN_TSF_SYNC_GET_TIMEOUT 2000
yuanl2746f072018-09-21 19:19:16 +080046#define WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS 500
47#define WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS 100
Subrat Dashf75d3d32019-08-23 22:27:37 +053048#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC
49#define WLAN_HDD_SOFTAP_INTERVAL_TIMES 1
50#else
51#define WLAN_HDD_SOFTAP_INTERVAL_TIMES 100
52#endif
Subrat Dashb1e61b22019-07-22 14:09:34 +053053#define OUTPUT_HIGH 1
54#define OUTPUT_LOW 0
yuanl2746f072018-09-21 19:19:16 +080055
Subrat Dash5f36fbe2019-02-12 16:28:14 +053056#ifdef WLAN_FEATURE_TSF_PLUS
57#ifdef WLAN_FEATURE_TSF_PLUS_NOIRQ
58static void hdd_update_timestamp(struct hdd_adapter *adapter);
59#else
60static void
61hdd_update_timestamp(struct hdd_adapter *adapter,
62 uint64_t target_time, uint64_t host_time);
63#endif
64#endif
65
Manikandan Mohandcc21ba2016-03-15 14:31:56 -070066/**
Yu Wangf5d5b5f2017-05-25 22:38:32 +080067 * enum hdd_tsf_op_result - result of tsf operation
Manikandan Mohandcc21ba2016-03-15 14:31:56 -070068 *
Yu Wangf5d5b5f2017-05-25 22:38:32 +080069 * HDD_TSF_OP_SUCC: succeed
70 * HDD_TSF_OP_FAIL: fail
Manikandan Mohandcc21ba2016-03-15 14:31:56 -070071 */
Yu Wangf5d5b5f2017-05-25 22:38:32 +080072enum hdd_tsf_op_result {
73 HDD_TSF_OP_SUCC,
74 HDD_TSF_OP_FAIL
75};
76
Yu Wang000dc2f2017-05-26 17:38:48 +080077#ifdef WLAN_FEATURE_TSF_PLUS
Subrat Dashb1e61b22019-07-22 14:09:34 +053078#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC
79#define WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL 1
80#else
yuanl2746f072018-09-21 19:19:16 +080081#define WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL 9
Subrat Dashb1e61b22019-07-22 14:09:34 +053082#endif
Jeff Johnson8f389862017-08-29 14:19:23 -070083static inline void hdd_set_th_sync_status(struct hdd_adapter *adapter,
Yu Wang000dc2f2017-05-26 17:38:48 +080084 bool initialized)
85{
86 qdf_atomic_set(&adapter->tsf_sync_ready_flag,
87 (initialized ? 1 : 0));
88}
89
Jeff Johnson8f389862017-08-29 14:19:23 -070090static inline bool hdd_get_th_sync_status(struct hdd_adapter *adapter)
Yu Wang000dc2f2017-05-26 17:38:48 +080091{
92 return qdf_atomic_read(&adapter->tsf_sync_ready_flag) != 0;
93}
94
95#else
Jeff Johnson8f389862017-08-29 14:19:23 -070096static inline bool hdd_get_th_sync_status(struct hdd_adapter *adapter)
Yu Wang000dc2f2017-05-26 17:38:48 +080097{
98 return true;
99}
100#endif
101
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800102static
Jeff Johnson8f389862017-08-29 14:19:23 -0700103enum hdd_tsf_get_state hdd_tsf_check_conn_state(struct hdd_adapter *adapter)
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700104{
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800105 enum hdd_tsf_get_state ret = TSF_RETURN;
Jeff Johnson40dae4e2017-08-29 14:00:25 -0700106 struct hdd_station_ctx *hdd_sta_ctx;
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700107
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700108 if (adapter->device_mode == QDF_STA_MODE ||
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800109 adapter->device_mode == QDF_P2P_CLIENT_MODE) {
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700110 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnsone7951512019-02-27 10:02:51 -0800111 if (hdd_sta_ctx->conn_info.conn_state !=
Manikandan Mohan5356c2b2016-04-03 15:51:35 -0700112 eConnectionState_Associated) {
113 hdd_err("failed to cap tsf, not connect with ap");
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800114 ret = TSF_STA_NOT_CONNECTED_NO_TSF;
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700115 }
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800116 } else if ((adapter->device_mode == QDF_SAP_MODE ||
117 adapter->device_mode == QDF_P2P_GO_MODE) &&
118 !(test_bit(SOFTAP_BSS_STARTED,
119 &adapter->event_flags))) {
Manikandan Mohan5356c2b2016-04-03 15:51:35 -0700120 hdd_err("Soft AP / P2p GO not beaconing");
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800121 ret = TSF_SAP_NOT_STARTED_NO_TSF;
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700122 }
123 return ret;
124}
125
Jeff Johnson8f389862017-08-29 14:19:23 -0700126static bool hdd_tsf_is_initialized(struct hdd_adapter *adapter)
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800127{
Jeff Johnson854cccd2017-08-28 11:39:24 -0700128 struct hdd_context *hddctx;
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800129
130 if (!adapter) {
131 hdd_err("invalid adapter");
132 return false;
133 }
134
135 hddctx = WLAN_HDD_GET_CTX(adapter);
136 if (!hddctx) {
137 hdd_err("invalid hdd context");
138 return false;
139 }
140
Yu Wang000dc2f2017-05-26 17:38:48 +0800141 if (!qdf_atomic_read(&hddctx->tsf_ready_flag) ||
142 !hdd_get_th_sync_status(adapter)) {
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800143 hdd_err("TSF is not initialized");
144 return false;
145 }
146
147 return true;
148}
149
Subrat Dashb1e61b22019-07-22 14:09:34 +0530150#if (defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && \
151 defined(WLAN_FEATURE_TSF_PLUS)) || \
Paul Zhangfaa929c2019-11-12 10:10:44 +0800152 defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) || \
153 defined(WLAN_FEATURE_TSF_TIMER_SYNC)
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700154/**
Manikandan Mohan5356c2b2016-04-03 15:51:35 -0700155 * hdd_tsf_reset_gpio() - Reset TSF GPIO used for host timer sync
156 * @adapter: pointer to adapter
157 *
158 * This function send WMI command to reset GPIO configured in FW after
159 * TSF get operation.
160 *
161 * Return: TSF_RETURN on Success, TSF_RESET_GPIO_FAIL on failure
162 */
Jeff Johnson85b5c112017-08-11 15:15:23 -0700163static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter)
Manikandan Mohan5356c2b2016-04-03 15:51:35 -0700164{
165 /* No GPIO Host timer sync for integrated WIFI Device */
166 return TSF_RETURN;
167}
yuanl2746f072018-09-21 19:19:16 +0800168
169/**
170 * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync
171 * @hdd_ctx: pointer to hdd context
172 *
173 * This function is a dummy function for adrastea arch
174 *
175 * Return: QDF_STATUS_SUCCESS on Success
176 */
177
178static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx)
179{
180 return QDF_STATUS_SUCCESS;
181}
Subrat Dash5f36fbe2019-02-12 16:28:14 +0530182#else
183static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter)
184{
185 int ret;
yuanl2746f072018-09-21 19:19:16 +0800186
Subrat Dash5f36fbe2019-02-12 16:28:14 +0530187 ret = wma_cli_set_command((int)adapter->vdev_id,
188 (int)GEN_PARAM_RESET_TSF_GPIO,
189 adapter->vdev_id,
190 GEN_CMD);
191
192 if (ret != 0) {
193 hdd_err("tsf reset GPIO fail ");
194 ret = TSF_RESET_GPIO_FAIL;
195 } else {
196 ret = TSF_RETURN;
197 }
198 return ret;
199}
200
201/**
202 * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync
203 * @hdd_ctx: pointer to hdd context
204 *
205 * This function check GPIO and set GPIO as IRQ to FW side on
206 * none Adrastea arch
207 *
208 * Return: QDF_STATUS_SUCCESS on Success, others on Failure.
209 */
210static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx)
211{
212 QDF_STATUS status;
213 uint32_t tsf_gpio_pin = TSF_GPIO_PIN_INVALID;
214
215 status = ucfg_fwol_get_tsf_gpio_pin(hdd_ctx->psoc, &tsf_gpio_pin);
216 if (QDF_IS_STATUS_ERROR(status))
217 return QDF_STATUS_E_INVAL;
218
219 if (tsf_gpio_pin == TSF_GPIO_PIN_INVALID)
220 return QDF_STATUS_E_INVAL;
221
222 status = sme_set_tsf_gpio(hdd_ctx->mac_handle,
223 tsf_gpio_pin);
224
225 return status;
226}
227#endif
228
229#ifdef WLAN_FEATURE_TSF_PLUS
Subrat Dashb1e61b22019-07-22 14:09:34 +0530230static bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd)
yuanl2746f072018-09-21 19:19:16 +0800231{
Manikandan Mohan0faf6282019-01-14 18:00:04 -0800232 uint32_t tsf_ptp_options;
233
234 if (hdd && QDF_IS_STATUS_SUCCESS(
235 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
236 return !!tsf_ptp_options;
237 else
238 return false;
yuanl2746f072018-09-21 19:19:16 +0800239}
240
241bool hdd_tsf_is_tx_set(struct hdd_context *hdd)
242{
Manikandan Mohand350c192018-11-29 14:01:12 -0800243 uint32_t tsf_ptp_options;
244
245 if (hdd && QDF_IS_STATUS_SUCCESS(
246 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
247 return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_TX;
248 else
249 return false;
yuanl2746f072018-09-21 19:19:16 +0800250}
251
252bool hdd_tsf_is_rx_set(struct hdd_context *hdd)
253{
Manikandan Mohand350c192018-11-29 14:01:12 -0800254 uint32_t tsf_ptp_options;
255
256 if (hdd && QDF_IS_STATUS_SUCCESS(
257 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
258 return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_RX;
259 else
260 return false;
yuanl2746f072018-09-21 19:19:16 +0800261}
262
263bool hdd_tsf_is_raw_set(struct hdd_context *hdd)
264{
Manikandan Mohand350c192018-11-29 14:01:12 -0800265 uint32_t tsf_ptp_options;
266
267 if (hdd && QDF_IS_STATUS_SUCCESS(
268 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
269 return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_RAW;
270 else
271 return false;
yuanl2746f072018-09-21 19:19:16 +0800272}
273
274bool hdd_tsf_is_dbg_fs_set(struct hdd_context *hdd)
275{
Manikandan Mohand350c192018-11-29 14:01:12 -0800276 uint32_t tsf_ptp_options;
277
278 if (hdd && QDF_IS_STATUS_SUCCESS(
279 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
280 return tsf_ptp_options & CFG_SET_TSF_DBG_FS;
281 else
282 return false;
yuanl2746f072018-09-21 19:19:16 +0800283}
Jiani Liu6d3b6a12019-05-08 15:15:06 +0800284
285bool hdd_tsf_is_tsf64_tx_set(struct hdd_context *hdd)
286{
287 uint32_t tsf_ptp_options;
288
289 if (hdd && QDF_IS_STATUS_SUCCESS(
290 ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options)))
291 return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_TSF64_TX;
292 else
293 return false;
294}
Subrat Dashb1e61b22019-07-22 14:09:34 +0530295#else
296
297static bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd)
298{
299 return false;
300}
301#endif
302
303#ifdef WLAN_FEATURE_TSF_PLUS
304static inline
305uint64_t hdd_get_monotonic_host_time(struct hdd_context *hdd_ctx)
306{
307 return hdd_tsf_is_raw_set(hdd_ctx) ?
308 ktime_get_ns() : ktime_get_real_ns();
309}
310#endif
311
312#if defined(WLAN_FEATURE_TSF_PLUS) && \
313 defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
Subrat Dash42155f62019-11-21 18:10:21 +0530314#define MAX_CONTINUOUS_RETRY_CNT 10
315static uint32_t
316hdd_wlan_retry_tsf_cap(struct hdd_adapter *adapter)
317{
318 struct hdd_context *hddctx;
319 int count = adapter->continuous_cap_retry_count;
320
321 hddctx = WLAN_HDD_GET_CTX(adapter);
322 if (count == MAX_CONTINUOUS_RETRY_CNT) {
323 hdd_debug("Max retry countr reached");
324 return 0;
325 }
326 qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
327 count++;
328 adapter->continuous_cap_retry_count = count;
329 return (count * WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS);
330}
331
Subrat Dashb1e61b22019-07-22 14:09:34 +0530332static void
Subrat Dash9ba2ff82019-11-27 18:36:45 +0530333hdd_wlan_restart_tsf_cap(struct hdd_adapter *adapter)
334{
335 struct hdd_context *hddctx;
336 int count = adapter->continuous_cap_retry_count;
337
338 hddctx = WLAN_HDD_GET_CTX(adapter);
339 if (count == MAX_CONTINUOUS_RETRY_CNT) {
340 hdd_debug("Restart TSF CAP");
341 qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
342 adapter->continuous_cap_retry_count = 0;
343 qdf_mc_timer_start(&adapter->host_target_sync_timer,
344 WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS);
345 }
346}
347
348static void
Subrat Dashb1e61b22019-07-22 14:09:34 +0530349hdd_update_host_time(struct hdd_adapter *adapter)
350{
351 struct hdd_context *hdd_ctx;
352 u64 host_time;
353 char *name = NULL;
354
355 hdd_ctx = adapter->hdd_ctx;
356
357 if (!hdd_tsf_is_initialized(adapter)) {
358 hdd_err("tsf is not init, exit");
359 return;
360 }
361
362 host_time = hdd_get_monotonic_host_time(hdd_ctx);
363 hdd_update_timestamp(adapter, 0, host_time);
364 name = adapter->dev->name;
365
366 hdd_debug("iface: %s - host_time: %llu",
367 (!name ? "none" : name), host_time);
368}
369
370static
371void hdd_tsf_ext_gpio_sync_work(void *data)
372{
373 QDF_STATUS status;
374 struct hdd_adapter *adapter;
375 struct hdd_context *hdd_ctx;
376 uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID;
377
378 adapter = data;
379 hdd_ctx = adapter->hdd_ctx;
380 status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc,
381 &tsf_sync_gpio_pin);
382 if (QDF_IS_STATUS_ERROR(status)) {
383 hdd_err("tsf sync gpio host pin error");
384 return;
385 }
386 gpio_set_value(tsf_sync_gpio_pin, OUTPUT_HIGH);
387 hdd_update_host_time(adapter);
388 usleep_range(50, 100);
389 gpio_set_value(tsf_sync_gpio_pin, OUTPUT_LOW);
390
391 status = wma_cli_set_command((int)adapter->vdev_id,
392 (int)GEN_PARAM_CAPTURE_TSF,
393 adapter->vdev_id, GEN_CMD);
394 if (status != QDF_STATUS_SUCCESS) {
395 hdd_err("cap tsf fail");
396 qdf_mc_timer_stop(&adapter->host_capture_req_timer);
397 qdf_mc_timer_destroy(&adapter->host_capture_req_timer);
398 }
399}
400
401static void
402hdd_tsf_gpio_sync_work_init(struct hdd_adapter *adapter)
403{
404 qdf_create_work(0, &adapter->gpio_tsf_sync_work,
405 hdd_tsf_ext_gpio_sync_work, adapter);
406}
407
408static void
409hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter *adapter)
410{
411 qdf_destroy_work(0, &adapter->gpio_tsf_sync_work);
412}
413
414static void
415hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter *adapter)
416{
417 qdf_cancel_work(&adapter->gpio_tsf_sync_work);
418}
419
420static void
421hdd_tsf_start_ext_gpio_sync(struct hdd_adapter *adapter)
422{
423 qdf_sched_work(0, &adapter->gpio_tsf_sync_work);
424}
425
426static bool hdd_tsf_cap_sync_send(struct hdd_adapter *adapter)
427{
428 hdd_tsf_start_ext_gpio_sync(adapter);
429 return true;
430}
431#elif defined(WLAN_FEATURE_TSF_PLUS) && \
432 !defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
Subrat Dash42155f62019-11-21 18:10:21 +0530433static uint32_t
434hdd_wlan_retry_tsf_cap(struct hdd_adapter *adapter)
435{
436 return 0;
437}
438
Subrat Dashb1e61b22019-07-22 14:09:34 +0530439static void
Subrat Dash9ba2ff82019-11-27 18:36:45 +0530440hdd_wlan_restart_tsf_cap(struct hdd_adapter *adapter)
441{
442}
443
444static void
Subrat Dashb1e61b22019-07-22 14:09:34 +0530445hdd_tsf_gpio_sync_work_init(struct hdd_adapter *adapter)
446{
447}
448
449static void
450hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter *adapter)
451{
452}
453
454static void
455hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter *adapter)
456{
457}
458
459static void
460hdd_tsf_start_ext_gpio_sync(struct hdd_adapter *adapter)
461{
462}
463
464static bool
465hdd_tsf_cap_sync_send(struct hdd_adapter *adapter)
466{
467 hdd_tsf_start_ext_gpio_sync(adapter);
468 return false;
469}
470
471#else
472static bool hdd_tsf_cap_sync_send(struct hdd_adapter *adapter)
473{
474 return false;
475}
Manikandan Mohan5356c2b2016-04-03 15:51:35 -0700476#endif
477
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800478static enum hdd_tsf_op_result hdd_capture_tsf_internal(
Jeff Johnson8f389862017-08-29 14:19:23 -0700479 struct hdd_adapter *adapter, uint32_t *buf, int len)
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700480{
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800481 int ret;
Jeff Johnson854cccd2017-08-28 11:39:24 -0700482 struct hdd_context *hddctx;
yuanl2746f072018-09-21 19:19:16 +0800483 qdf_mc_timer_t *cap_timer;
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700484
Jeff Johnsond36fa332019-03-18 13:42:25 -0700485 if (!adapter || !buf) {
Manikandan Mohan5356c2b2016-04-03 15:51:35 -0700486 hdd_err("invalid pointer");
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800487 return HDD_TSF_OP_FAIL;
488 }
489
490 if (len != 1)
491 return HDD_TSF_OP_FAIL;
492
493 hddctx = WLAN_HDD_GET_CTX(adapter);
494 if (!hddctx) {
495 hdd_err("invalid hdd context");
496 return HDD_TSF_OP_FAIL;
497 }
498
499 if (!hdd_tsf_is_initialized(adapter)) {
500 buf[0] = TSF_NOT_READY;
501 return HDD_TSF_OP_SUCC;
502 }
503
504 buf[0] = hdd_tsf_check_conn_state(adapter);
505 if (buf[0] != TSF_RETURN)
506 return HDD_TSF_OP_SUCC;
507
508 if (qdf_atomic_inc_return(&hddctx->cap_tsf_flag) > 1) {
509 hdd_err("current in capture state");
510 buf[0] = TSF_CURRENT_IN_CAP_STATE;
511 return HDD_TSF_OP_SUCC;
512 }
513
514 /* record adapter for cap_tsf_irq_handler */
515 hddctx->cap_tsf_context = adapter;
516
yuanl2746f072018-09-21 19:19:16 +0800517 hdd_info("+ioctl issue cap tsf cmd");
518 cap_timer = &adapter->host_capture_req_timer;
519 qdf_mc_timer_init(cap_timer, QDF_TIMER_TYPE_SW,
520 hdd_capture_req_timer_expired_handler,
521 (void *)adapter);
522 qdf_mc_timer_start(cap_timer, WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS);
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800523
524 /* Reset TSF value for new capture */
525 adapter->cur_target_time = 0;
526
527 buf[0] = TSF_RETURN;
528 init_completion(&tsf_sync_get_completion_evt);
Subrat Dashb1e61b22019-07-22 14:09:34 +0530529
530 if (hdd_tsf_cap_sync_send(adapter))
531 return HDD_TSF_OP_SUCC;
532
Jeff Johnson9597f3b2019-02-04 14:27:56 -0800533 ret = wma_cli_set_command((int)adapter->vdev_id,
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800534 (int)GEN_PARAM_CAPTURE_TSF,
Jeff Johnson9597f3b2019-02-04 14:27:56 -0800535 adapter->vdev_id, GEN_CMD);
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800536 if (QDF_STATUS_SUCCESS != ret) {
537 hdd_err("cap tsf fail");
538 buf[0] = TSF_CAPTURE_FAIL;
539 hddctx->cap_tsf_context = NULL;
540 qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
yuanl2746f072018-09-21 19:19:16 +0800541 qdf_mc_timer_stop(&adapter->host_capture_req_timer);
542 qdf_mc_timer_destroy(&adapter->host_capture_req_timer);
543
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800544 return HDD_TSF_OP_SUCC;
545 }
yuanl2746f072018-09-21 19:19:16 +0800546 hdd_info("-ioctl return cap tsf cmd");
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800547 return HDD_TSF_OP_SUCC;
548}
549
550static enum hdd_tsf_op_result hdd_indicate_tsf_internal(
Jeff Johnson8f389862017-08-29 14:19:23 -0700551 struct hdd_adapter *adapter, uint32_t *buf, int len)
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800552{
553 int ret;
Jeff Johnson854cccd2017-08-28 11:39:24 -0700554 struct hdd_context *hddctx;
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800555
556 if (!adapter || !buf) {
557 hdd_err("invalid pointer");
558 return HDD_TSF_OP_FAIL;
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700559 }
560
561 if (len != 3)
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800562 return HDD_TSF_OP_FAIL;
563
564 hddctx = WLAN_HDD_GET_CTX(adapter);
565 if (!hddctx) {
566 hdd_err("invalid hdd context");
567 return HDD_TSF_OP_FAIL;
568 }
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700569
570 buf[1] = 0;
571 buf[2] = 0;
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800572
573 if (!hdd_tsf_is_initialized(adapter)) {
574 buf[0] = TSF_NOT_READY;
575 return HDD_TSF_OP_SUCC;
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700576 }
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800577
578 buf[0] = hdd_tsf_check_conn_state(adapter);
579 if (buf[0] != TSF_RETURN)
580 return HDD_TSF_OP_SUCC;
581
582 if (adapter->cur_target_time == 0) {
Manikandan Mohan5356c2b2016-04-03 15:51:35 -0700583 hdd_info("TSF value not received");
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700584 buf[0] = TSF_NOT_RETURNED_BY_FW;
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800585 return HDD_TSF_OP_SUCC;
Jeff Johnsona5fb2182017-10-06 20:27:38 -0700586 }
587
588 buf[0] = TSF_RETURN;
589 buf[1] = (uint32_t)(adapter->cur_target_time & 0xffffffff);
590 buf[2] = (uint32_t)((adapter->cur_target_time >> 32) &
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800591 0xffffffff);
592
Jeff Johnsona5fb2182017-10-06 20:27:38 -0700593 if (!qdf_atomic_read(&hddctx->cap_tsf_flag)) {
594 hdd_info("old: status=%u, tsf_low=%u, tsf_high=%u",
595 buf[0], buf[1], buf[2]);
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800596 return HDD_TSF_OP_SUCC;
Manikandan Mohandcc21ba2016-03-15 14:31:56 -0700597 }
Jeff Johnsona5fb2182017-10-06 20:27:38 -0700598
599 ret = hdd_tsf_reset_gpio(adapter);
600 if (0 != ret) {
601 hdd_err("reset tsf gpio fail");
602 buf[0] = TSF_RESET_GPIO_FAIL;
603 return HDD_TSF_OP_SUCC;
604 }
605 hddctx->cap_tsf_context = NULL;
606 qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
607 hdd_info("get tsf cmd,status=%u, tsf_low=%u, tsf_high=%u",
608 buf[0], buf[1], buf[2]);
609
610 return HDD_TSF_OP_SUCC;
Yu Wangf5d5b5f2017-05-25 22:38:32 +0800611}
612
Yu Wang000dc2f2017-05-26 17:38:48 +0800613#ifdef WLAN_FEATURE_TSF_PLUS
614/* unit for target time: us; host time: ns */
615#define HOST_TO_TARGET_TIME_RATIO NSEC_PER_USEC
gaolezc2b72082017-10-30 15:29:59 +0800616#define MAX_ALLOWED_DEVIATION_NS (100 * NSEC_PER_USEC)
Yu Wang000dc2f2017-05-26 17:38:48 +0800617#define MAX_CONTINUOUS_ERROR_CNT 3
Yu Wang04ccd762017-05-31 19:29:43 +0800618
619/* to distinguish 32-bit overflow case, this inverval should:
620 * equal or less than (1/2 * OVERFLOW_INDICATOR32 us)
621 */
Subrat Dashb1e61b22019-07-22 14:09:34 +0530622#if defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ) || \
623 defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
Subrat Dash5f36fbe2019-02-12 16:28:14 +0530624#define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 2
625#else
guangde87e17202019-09-20 18:18:28 +0800626#define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 4
Subrat Dash5f36fbe2019-02-12 16:28:14 +0530627#endif
Yu Wang04ccd762017-05-31 19:29:43 +0800628#define OVERFLOW_INDICATOR32 (((int64_t)0x1) << 32)
gaolezc2b72082017-10-30 15:29:59 +0800629#define CAP_TSF_TIMER_FIX_SEC 1
Yu Wang000dc2f2017-05-26 17:38:48 +0800630
631/**
632 * TS_STATUS - timestamp status
633 *
634 * HDD_TS_STATUS_WAITING: one of the stamp-pair
635 * is not updated
636 * HDD_TS_STATUS_READY: valid tstamp-pair
637 * HDD_TS_STATUS_INVALID: invalid tstamp-pair
638 */
639enum hdd_ts_status {
640 HDD_TS_STATUS_WAITING,
641 HDD_TS_STATUS_READY,
642 HDD_TS_STATUS_INVALID
643};
644
645static
Jeff Johnson8f389862017-08-29 14:19:23 -0700646enum hdd_tsf_op_result __hdd_start_tsf_sync(struct hdd_adapter *adapter)
Yu Wang000dc2f2017-05-26 17:38:48 +0800647{
648 QDF_STATUS ret;
649
650 if (!hdd_get_th_sync_status(adapter)) {
651 hdd_err("Host Target sync has not initialized");
652 return HDD_TSF_OP_FAIL;
653 }
654
Subrat Dashb1e61b22019-07-22 14:09:34 +0530655 hdd_tsf_gpio_sync_work_init(adapter);
Yu Wang000dc2f2017-05-26 17:38:48 +0800656 ret = qdf_mc_timer_start(&adapter->host_target_sync_timer,
657 WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS);
658 if (ret != QDF_STATUS_SUCCESS && ret != QDF_STATUS_E_ALREADY) {
659 hdd_err("Failed to start timer, ret: %d", ret);
660 return HDD_TSF_OP_FAIL;
661 }
662 return HDD_TSF_OP_SUCC;
663}
664
665static
Jeff Johnson8f389862017-08-29 14:19:23 -0700666enum hdd_tsf_op_result __hdd_stop_tsf_sync(struct hdd_adapter *adapter)
Yu Wang000dc2f2017-05-26 17:38:48 +0800667{
668 QDF_STATUS ret;
669
670 if (!hdd_get_th_sync_status(adapter)) {
671 hdd_err("Host Target sync has not initialized");
672 return HDD_TSF_OP_SUCC;
673 }
674
675 ret = qdf_mc_timer_stop(&adapter->host_target_sync_timer);
676 if (ret != QDF_STATUS_SUCCESS) {
677 hdd_err("Failed to stop timer, ret: %d", ret);
678 return HDD_TSF_OP_FAIL;
679 }
Subrat Dashb1e61b22019-07-22 14:09:34 +0530680 hdd_tsf_stop_ext_gpio_sync(adapter);
681 hdd_tsf_gpio_sync_work_deinit(adapter);
Yu Wang000dc2f2017-05-26 17:38:48 +0800682 return HDD_TSF_OP_SUCC;
683}
684
Jeff Johnson8f389862017-08-29 14:19:23 -0700685static inline void hdd_reset_timestamps(struct hdd_adapter *adapter)
Yu Wang000dc2f2017-05-26 17:38:48 +0800686{
687 qdf_spin_lock_bh(&adapter->host_target_sync_lock);
688 adapter->cur_host_time = 0;
689 adapter->cur_target_time = 0;
690 adapter->last_host_time = 0;
691 adapter->last_target_time = 0;
692 qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
693}
694
695/**
696 * hdd_check_timestamp_status() - return the tstamp status
697 *
698 * @last_target_time: the last saved target time
yuanl69575bb2019-01-24 19:16:28 +0800699 * @last_sync_time: the last saved sync time
Yu Wang000dc2f2017-05-26 17:38:48 +0800700 * @cur_target_time : new target time
yuanl69575bb2019-01-24 19:16:28 +0800701 * @cur_sync_time : new sync time
Yu Wang000dc2f2017-05-26 17:38:48 +0800702 *
yuanl69575bb2019-01-24 19:16:28 +0800703 * This function check the new timstamp-pair(cur_host_time/cur_target_time)or
704 * (cur_qtime_time/cur_target_time)
Yu Wang000dc2f2017-05-26 17:38:48 +0800705 * Return:
yuanl69575bb2019-01-24 19:16:28 +0800706 * HDD_TS_STATUS_WAITING: cur_sync_time or cur_sync_time is 0
Yu Wang000dc2f2017-05-26 17:38:48 +0800707 * HDD_TS_STATUS_READY: cur_target_time/cur_host_time is a valid pair,
708 * and can be saved
yuanl69575bb2019-01-24 19:16:28 +0800709 * HDD_TS_STATUS_INVALID: cur_target_time/cur_sync_time is a invalid pair,
Yu Wang000dc2f2017-05-26 17:38:48 +0800710 * should be discard
711 */
712static
713enum hdd_ts_status hdd_check_timestamp_status(
714 uint64_t last_target_time,
yuanl69575bb2019-01-24 19:16:28 +0800715 uint64_t last_sync_time,
Yu Wang000dc2f2017-05-26 17:38:48 +0800716 uint64_t cur_target_time,
yuanl69575bb2019-01-24 19:16:28 +0800717 uint64_t cur_sync_time)
Yu Wang000dc2f2017-05-26 17:38:48 +0800718{
yuanl69575bb2019-01-24 19:16:28 +0800719 uint64_t delta_ns, delta_target_time, delta_sync_time;
Yu Wang000dc2f2017-05-26 17:38:48 +0800720
721 /* one or more are not updated, need to wait */
yuanl69575bb2019-01-24 19:16:28 +0800722 if (cur_target_time == 0 || cur_sync_time == 0)
Yu Wang000dc2f2017-05-26 17:38:48 +0800723 return HDD_TS_STATUS_WAITING;
724
725 /* init value, it's the first time to update the pair */
yuanl69575bb2019-01-24 19:16:28 +0800726 if (last_target_time == 0 && last_sync_time == 0)
Yu Wang000dc2f2017-05-26 17:38:48 +0800727 return HDD_TS_STATUS_READY;
728
729 /* the new values should be greater than the saved values */
730 if ((cur_target_time <= last_target_time) ||
yuanl69575bb2019-01-24 19:16:28 +0800731 (cur_sync_time <= last_sync_time)) {
Yu Wang000dc2f2017-05-26 17:38:48 +0800732 hdd_err("Invalid timestamps!last_target_time: %llu;"
yuanl69575bb2019-01-24 19:16:28 +0800733 "last_sync_time: %llu; cur_target_time: %llu;"
734 "cur_sync_time: %llu",
735 last_target_time, last_sync_time,
736 cur_target_time, cur_sync_time);
Yu Wang000dc2f2017-05-26 17:38:48 +0800737 return HDD_TS_STATUS_INVALID;
738 }
739
740 delta_target_time = (cur_target_time - last_target_time) *
yuanl69575bb2019-01-24 19:16:28 +0800741 NSEC_PER_USEC;
742 delta_sync_time = cur_sync_time - last_sync_time;
Yu Wang000dc2f2017-05-26 17:38:48 +0800743
744 /*
745 * DO NOT use abs64() , a big uint64 value might be turned to
746 * a small int64 value
747 */
yuanl69575bb2019-01-24 19:16:28 +0800748 delta_ns = ((delta_target_time > delta_sync_time) ?
749 (delta_target_time - delta_sync_time) :
750 (delta_sync_time - delta_target_time));
751 hdd_warn("timestamps deviation - delta: %llu ns", delta_ns);
Yu Wang000dc2f2017-05-26 17:38:48 +0800752 /* the deviation should be smaller than a threshold */
753 if (delta_ns > MAX_ALLOWED_DEVIATION_NS) {
yuanl2746f072018-09-21 19:19:16 +0800754 hdd_warn("Invalid timestamps - delta: %llu ns", delta_ns);
Yu Wang000dc2f2017-05-26 17:38:48 +0800755 return HDD_TS_STATUS_INVALID;
756 }
757 return HDD_TS_STATUS_READY;
758}
759
Jeff Johnson8f389862017-08-29 14:19:23 -0700760static inline bool hdd_tsf_is_in_cap(struct hdd_adapter *adapter)
Yu Wang04ccd762017-05-31 19:29:43 +0800761{
Jeff Johnson854cccd2017-08-28 11:39:24 -0700762 struct hdd_context *hddctx;
Yu Wang04ccd762017-05-31 19:29:43 +0800763
764 hddctx = WLAN_HDD_GET_CTX(adapter);
765 if (!hddctx)
766 return false;
767
768 return qdf_atomic_read(&hddctx->cap_tsf_flag) > 0;
769}
770
771/* define 64bit plus/minus to deal with overflow */
772static inline int hdd_64bit_plus(uint64_t x, int64_t y, uint64_t *ret)
773{
774 if ((y < 0 && (-y) > x) ||
775 (y > 0 && (y > U64_MAX - x))) {
776 *ret = 0;
777 return -EINVAL;
778 }
779
780 *ret = x + y;
781 return 0;
782}
783
Yu Wang0ea10172017-06-02 13:40:52 +0800784static inline int hdd_uint64_plus(uint64_t x, uint64_t y, uint64_t *ret)
785{
786 if (!ret)
787 return -EINVAL;
788
789 if (x > (U64_MAX - y)) {
790 *ret = 0;
791 return -EINVAL;
792 }
793
794 *ret = x + y;
795 return 0;
796}
797
798static inline int hdd_uint64_minus(uint64_t x, uint64_t y, uint64_t *ret)
799{
800 if (!ret)
801 return -EINVAL;
802
803 if (x < y) {
804 *ret = 0;
805 return -EINVAL;
806 }
807
808 *ret = x - y;
809 return 0;
810}
811
Yu Wang04ccd762017-05-31 19:29:43 +0800812static inline int32_t hdd_get_hosttime_from_targettime(
Jeff Johnson8f389862017-08-29 14:19:23 -0700813 struct hdd_adapter *adapter, uint64_t target_time,
Yu Wang04ccd762017-05-31 19:29:43 +0800814 uint64_t *host_time)
815{
816 int32_t ret = -EINVAL;
817 int64_t delta32_target;
818 bool in_cap_state;
gaolezd11c7c52018-03-28 15:04:13 +0800819 int64_t normal_interval_target;
Yu Wang04ccd762017-05-31 19:29:43 +0800820
821 in_cap_state = hdd_tsf_is_in_cap(adapter);
822
823 /*
824 * To avoid check the lock when it's not capturing tsf
825 * (the tstamp-pair won't be changed)
826 */
827 if (in_cap_state)
828 qdf_spin_lock_bh(&adapter->host_target_sync_lock);
829
Subrat Dash9ba2ff82019-11-27 18:36:45 +0530830 hdd_wlan_restart_tsf_cap(adapter);
Yu Wang04ccd762017-05-31 19:29:43 +0800831 /* at present, target_time is only 32bit in fact */
832 delta32_target = (int64_t)((target_time & U32_MAX) -
833 (adapter->last_target_time & U32_MAX));
834
yuanl45a15262018-11-11 01:11:47 +0800835 normal_interval_target = WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC *
836 qdf_do_div(NSEC_PER_SEC, HOST_TO_TARGET_TIME_RATIO);
gaolezd11c7c52018-03-28 15:04:13 +0800837
Yu Wang04ccd762017-05-31 19:29:43 +0800838 if (delta32_target <
gaolezd11c7c52018-03-28 15:04:13 +0800839 (normal_interval_target - OVERFLOW_INDICATOR32))
Yu Wang04ccd762017-05-31 19:29:43 +0800840 delta32_target += OVERFLOW_INDICATOR32;
841 else if (delta32_target >
gaolezd11c7c52018-03-28 15:04:13 +0800842 (OVERFLOW_INDICATOR32 - normal_interval_target))
Yu Wang04ccd762017-05-31 19:29:43 +0800843 delta32_target -= OVERFLOW_INDICATOR32;
844
845 ret = hdd_64bit_plus(adapter->last_host_time,
846 HOST_TO_TARGET_TIME_RATIO * delta32_target,
847 host_time);
848
849 if (in_cap_state)
850 qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
851
852 return ret;
853}
854
Yu Wang0ea10172017-06-02 13:40:52 +0800855static inline int32_t hdd_get_targettime_from_hosttime(
Jeff Johnson8f389862017-08-29 14:19:23 -0700856 struct hdd_adapter *adapter, uint64_t host_time,
Yu Wang0ea10172017-06-02 13:40:52 +0800857 uint64_t *target_time)
858{
859 int32_t ret = -EINVAL;
860 bool in_cap_state;
861
862 if (!adapter || host_time == 0)
863 return ret;
864
865 in_cap_state = hdd_tsf_is_in_cap(adapter);
866 if (in_cap_state)
867 qdf_spin_lock_bh(&adapter->host_target_sync_lock);
868
869 if (host_time < adapter->last_host_time)
870 ret = hdd_uint64_minus(adapter->last_target_time,
Yu Wangc9ef24f2017-09-15 18:37:07 +0800871 qdf_do_div(adapter->last_host_time -
872 host_time,
873 HOST_TO_TARGET_TIME_RATIO),
Yu Wang0ea10172017-06-02 13:40:52 +0800874 target_time);
875 else
876 ret = hdd_uint64_plus(adapter->last_target_time,
Yu Wangc9ef24f2017-09-15 18:37:07 +0800877 qdf_do_div(host_time -
878 adapter->last_host_time,
879 HOST_TO_TARGET_TIME_RATIO),
Yu Wang0ea10172017-06-02 13:40:52 +0800880 target_time);
881
882 if (in_cap_state)
883 qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
884
885 return ret;
886}
887
Jiani Liua8fd1702019-05-01 10:07:10 +0800888/**
889 * hdd_get_soctime_from_tsf64time() - return get status
890 *
891 * @adapter: Adapter pointer
892 * @tsf64_time: current tsf64time, us
893 * @soc_time: current soc time(qtime), ns
894 *
895 * This function get current soc time from current tsf64 time
896 * Returun int32_t value to tell get success or fail.
897 *
898 * Return:
899 * 0: success
900 * other: fail
901 *
902 */
903static inline int32_t hdd_get_soctime_from_tsf64time(
904 struct hdd_adapter *adapter, uint64_t tsf64_time,
905 uint64_t *soc_time)
906{
907 int32_t ret = -EINVAL;
908 uint64_t delta64_tsf64time;
909 uint64_t delta64_soctime;
910 bool in_cap_state;
911
912 in_cap_state = hdd_tsf_is_in_cap(adapter);
913
914 /*
915 * To avoid check the lock when it's not capturing tsf
916 * (the tstamp-pair won't be changed)
917 */
918 if (in_cap_state)
919 qdf_spin_lock_bh(&adapter->host_target_sync_lock);
920
921 /* at present, target_time is 64bit (g_tsf64), us*/
guangde45e45e72019-07-12 10:21:31 +0800922 if (tsf64_time > adapter->last_target_global_tsf_time) {
Jiani Liua8fd1702019-05-01 10:07:10 +0800923 delta64_tsf64time = tsf64_time -
guangde45e45e72019-07-12 10:21:31 +0800924 adapter->last_target_global_tsf_time;
925 delta64_soctime = delta64_tsf64time * NSEC_PER_USEC;
926
927 /* soc_time (ns)*/
928 ret = hdd_uint64_plus(adapter->last_tsf_sync_soc_time,
929 delta64_soctime, soc_time);
930 } else {
931 delta64_tsf64time = adapter->last_target_global_tsf_time -
932 tsf64_time;
933 delta64_soctime = delta64_tsf64time * NSEC_PER_USEC;
934
935 /* soc_time (ns)*/
936 ret = hdd_uint64_minus(adapter->last_tsf_sync_soc_time,
937 delta64_soctime, soc_time);
Jiani Liua8fd1702019-05-01 10:07:10 +0800938 }
939
Jiani Liua8fd1702019-05-01 10:07:10 +0800940 if (in_cap_state)
941 qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
942
943 return ret;
944}
945
Yu Wang000dc2f2017-05-26 17:38:48 +0800946static void hdd_capture_tsf_timer_expired_handler(void *arg)
947{
948 uint32_t tsf_op_resp;
Jeff Johnson8f389862017-08-29 14:19:23 -0700949 struct hdd_adapter *adapter;
Yu Wang000dc2f2017-05-26 17:38:48 +0800950
951 if (!arg)
952 return;
953
Jeff Johnson8f389862017-08-29 14:19:23 -0700954 adapter = (struct hdd_adapter *)arg;
Yu Wang000dc2f2017-05-26 17:38:48 +0800955 hdd_capture_tsf_internal(adapter, &tsf_op_resp, 1);
956}
957
yuanl2746f072018-09-21 19:19:16 +0800958#ifndef WLAN_FEATURE_TSF_PLUS_NOIRQ
Subrat Dashb1e61b22019-07-22 14:09:34 +0530959#ifndef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC
Yu Wang000dc2f2017-05-26 17:38:48 +0800960static irqreturn_t hdd_tsf_captured_irq_handler(int irq, void *arg)
961{
Jeff Johnson8f389862017-08-29 14:19:23 -0700962 struct hdd_adapter *adapter;
Jeff Johnson854cccd2017-08-28 11:39:24 -0700963 struct hdd_context *hdd_ctx;
Yu Wang000dc2f2017-05-26 17:38:48 +0800964 uint64_t host_time;
965 char *name = NULL;
966
967 if (!arg)
968 return IRQ_NONE;
969
Subrat Dash5f36fbe2019-02-12 16:28:14 +0530970 if (irq != tsf_gpio_irq_num)
971 return IRQ_NONE;
972
Jeff Johnson854cccd2017-08-28 11:39:24 -0700973 hdd_ctx = (struct hdd_context *)arg;
Yu Wang66a250b2017-07-19 11:46:40 +0800974 host_time = hdd_get_monotonic_host_time(hdd_ctx);
Yu Wang000dc2f2017-05-26 17:38:48 +0800975
976 adapter = hdd_ctx->cap_tsf_context;
977 if (!adapter)
978 return IRQ_HANDLED;
979
980 if (!hdd_tsf_is_initialized(adapter)) {
981 hdd_err("tsf is not init, ignore irq");
982 return IRQ_HANDLED;
983 }
984
985 hdd_update_timestamp(adapter, 0, host_time);
986 if (adapter->dev)
987 name = adapter->dev->name;
988
989 hdd_info("irq: %d - iface: %s - host_time: %llu",
990 irq, (!name ? "none" : name), host_time);
991
992 return IRQ_HANDLED;
993}
yuanl2746f072018-09-21 19:19:16 +0800994#endif
Subrat Dashb1e61b22019-07-22 14:09:34 +0530995#endif
yuanl2746f072018-09-21 19:19:16 +0800996
997void hdd_capture_req_timer_expired_handler(void *arg)
998{
999 struct hdd_adapter *adapter;
1000 struct hdd_context *hdd_ctx;
1001 QDF_TIMER_STATE capture_req_timer_status;
1002 qdf_mc_timer_t *sync_timer;
1003 int interval;
1004 int ret;
1005
1006 if (!arg)
1007 return;
1008 adapter = (struct hdd_adapter *)arg;
1009
1010 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1011 if (!hdd_ctx) {
1012 hdd_warn("invalid hdd context");
1013 return;
1014 }
1015
1016 if (!hdd_tsf_is_initialized(adapter)) {
1017 qdf_mc_timer_destroy(&adapter->host_capture_req_timer);
1018 hdd_warn("tsf not init");
1019 return;
1020 }
1021
1022 qdf_spin_lock_bh(&adapter->host_target_sync_lock);
1023 adapter->cur_host_time = 0;
1024 adapter->cur_target_time = 0;
1025 qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
1026
1027 ret = hdd_tsf_reset_gpio(adapter);
1028 if (0 != ret)
1029 hdd_info("reset tsf gpio fail");
1030
1031 hdd_ctx->cap_tsf_context = NULL;
1032 qdf_atomic_set(&hdd_ctx->cap_tsf_flag, 0);
1033 qdf_mc_timer_destroy(&adapter->host_capture_req_timer);
1034
1035 sync_timer = &adapter->host_target_sync_timer;
1036 capture_req_timer_status =
1037 qdf_mc_timer_get_current_state(sync_timer);
1038
1039 if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) {
1040 hdd_warn("invalid timer status");
1041 return;
1042 }
1043
1044 interval = WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL * MSEC_PER_SEC;
1045 qdf_mc_timer_start(sync_timer, interval);
1046}
Yu Wang000dc2f2017-05-26 17:38:48 +08001047
yuanl69575bb2019-01-24 19:16:28 +08001048#ifdef WLAN_FEATURE_TSF_PLUS_NOIRQ
1049static void hdd_update_timestamp(struct hdd_adapter *adapter)
1050{
1051 int interval = 0;
1052 enum hdd_ts_status sync_status;
1053
1054 if (!adapter)
1055 return;
1056
1057 /* on ADREASTEA ach, Qtime is used to sync host and tsf time as a
1058 * intermedia there is no IRQ to sync up TSF-HOST, so host time in ns
1059 * and target in us will be updated at the same time in WMI command
1060 * callback
1061 */
1062
1063 qdf_spin_lock_bh(&adapter->host_target_sync_lock);
1064 sync_status =
1065 hdd_check_timestamp_status(adapter->last_target_time,
1066 adapter->last_tsf_sync_soc_time,
1067 adapter->cur_target_time,
1068 adapter->cur_tsf_sync_soc_time);
1069 hdd_info("sync_status %d", sync_status);
1070 switch (sync_status) {
1071 case HDD_TS_STATUS_INVALID:
1072 if (++adapter->continuous_error_count <
1073 MAX_CONTINUOUS_ERROR_CNT) {
1074 interval =
1075 WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS;
1076 adapter->cur_target_time = 0;
1077 adapter->cur_tsf_sync_soc_time = 0;
1078 break;
1079 }
1080 hdd_warn("Reach the max continuous error count");
1081 /*
1082 * fall through:
1083 * If reach MAX_CONTINUOUS_ERROR_CNT, treat it as a
1084 * valid pair
1085 */
1086 case HDD_TS_STATUS_READY:
1087 adapter->last_target_time = adapter->cur_target_time;
Jiani Liua8fd1702019-05-01 10:07:10 +08001088 adapter->last_target_global_tsf_time =
1089 adapter->cur_target_global_tsf_time;
yuanl69575bb2019-01-24 19:16:28 +08001090 adapter->last_tsf_sync_soc_time =
1091 adapter->cur_tsf_sync_soc_time;
1092 adapter->cur_target_time = 0;
Jiani Liua8fd1702019-05-01 10:07:10 +08001093 adapter->cur_target_global_tsf_time = 0;
yuanl69575bb2019-01-24 19:16:28 +08001094 adapter->cur_tsf_sync_soc_time = 0;
Jiani Liua8fd1702019-05-01 10:07:10 +08001095 hdd_info("ts-pair updated: target: %llu; g_target:%llu, Qtime: %llu",
yuanl69575bb2019-01-24 19:16:28 +08001096 adapter->last_target_time,
Jiani Liua8fd1702019-05-01 10:07:10 +08001097 adapter->last_target_global_tsf_time,
yuanl69575bb2019-01-24 19:16:28 +08001098 adapter->last_tsf_sync_soc_time);
1099
1100 /*
1101 * TSF-HOST need to be updated in at most
1102 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, it couldn't be achieved
1103 * if the timer interval is also
1104 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, due to processing or
1105 * schedule delay. So deduct several seconds from
1106 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC.
1107 * Without this change, hdd_get_hosttime_from_targettime() will
1108 * get wrong host time when it's longer than
1109 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last
1110 * TSF-HOST update.
1111 */
1112 interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC -
1113 CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC;
yuanl69575bb2019-01-24 19:16:28 +08001114
1115 adapter->continuous_error_count = 0;
Subrat Dash42155f62019-11-21 18:10:21 +05301116 adapter->continuous_cap_retry_count = 0;
yuanl69575bb2019-01-24 19:16:28 +08001117 hdd_debug("ts-pair updated: interval: %d",
1118 interval);
1119 break;
1120 case HDD_TS_STATUS_WAITING:
1121 interval = 0;
1122 hdd_warn("TS status is waiting due to one or more pair not updated");
1123 break;
1124 }
1125 qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
1126
1127 if (interval > 0)
1128 qdf_mc_timer_start(&adapter->host_target_sync_timer, interval);
1129}
1130
1131static ssize_t __hdd_wlan_tsf_show(struct device *dev,
1132 struct device_attribute *attr, char *buf)
1133{
1134 struct hdd_station_ctx *hdd_sta_ctx;
1135 struct hdd_adapter *adapter;
1136 struct hdd_context *hdd_ctx;
Jiani Liuef39b962019-05-30 13:24:59 +08001137 uint64_t tsf_sync_qtime, host_time, reg_qtime, qtime;
yuanl69575bb2019-01-24 19:16:28 +08001138 ssize_t size;
1139
1140 struct net_device *net_dev = container_of(dev, struct net_device, dev);
1141
1142 adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
1143 if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC)
1144 return scnprintf(buf, PAGE_SIZE, "Invalid device\n");
1145
1146 if (!hdd_get_th_sync_status(adapter))
1147 return scnprintf(buf, PAGE_SIZE,
1148 "TSF sync is not initialized\n");
1149
1150 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnsone7951512019-02-27 10:02:51 -08001151 if (eConnectionState_Associated != hdd_sta_ctx->conn_info.conn_state &&
yuanl69575bb2019-01-24 19:16:28 +08001152 (adapter->device_mode == QDF_STA_MODE ||
1153 adapter->device_mode == QDF_P2P_CLIENT_MODE))
1154 return scnprintf(buf, PAGE_SIZE, "NOT connected\n");
1155
1156 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1157
1158 if (!hdd_ctx)
1159 return scnprintf(buf, PAGE_SIZE, "Invalid HDD context\n");
1160
1161 tsf_sync_qtime = adapter->last_tsf_sync_soc_time;
1162 do_div(tsf_sync_qtime, NSEC_PER_USEC);
1163
Jiani Liuef39b962019-05-30 13:24:59 +08001164 reg_qtime = qdf_get_log_timestamp();
1165 host_time = hdd_get_monotonic_host_time(hdd_ctx);
1166
1167 qtime = qdf_log_timestamp_to_usecs(reg_qtime);
1168 do_div(host_time, NSEC_PER_USEC);
1169
yuanl69575bb2019-01-24 19:16:28 +08001170 if (adapter->device_mode == QDF_STA_MODE ||
1171 adapter->device_mode == QDF_P2P_CLIENT_MODE) {
Jiani Liuef39b962019-05-30 13:24:59 +08001172 size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM %llu %llu\n",
yuanl69575bb2019-01-24 19:16:28 +08001173 buf, adapter->last_target_time,
1174 tsf_sync_qtime,
Jiani Liuef39b962019-05-30 13:24:59 +08001175 hdd_sta_ctx->conn_info.bssid.bytes,
1176 qtime, host_time);
yuanl69575bb2019-01-24 19:16:28 +08001177 } else {
Jiani Liuef39b962019-05-30 13:24:59 +08001178 size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM %llu %llu\n",
yuanl69575bb2019-01-24 19:16:28 +08001179 buf, adapter->last_target_time,
1180 tsf_sync_qtime,
Jiani Liuef39b962019-05-30 13:24:59 +08001181 adapter->mac_addr.bytes,
1182 qtime, host_time);
yuanl69575bb2019-01-24 19:16:28 +08001183 }
1184
1185 return size;
1186}
1187
1188static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
1189{
1190 uint32_t tsf_op_resp[3];
1191 struct hdd_context *hddctx;
1192
1193 hddctx = WLAN_HDD_GET_CTX(adapter);
1194 hdd_indicate_tsf_internal(adapter, tsf_op_resp, 3);
1195 hdd_update_timestamp(adapter);
1196}
1197#else
1198static void hdd_update_timestamp(struct hdd_adapter *adapter,
1199 uint64_t target_time, uint64_t host_time)
1200{
1201 int interval = 0;
1202 enum hdd_ts_status sync_status;
1203
1204 if (!adapter)
1205 return;
1206
1207 /* host time is updated in IRQ context, it's always before target time,
1208 * and so no need to try update last_host_time at present;
1209 * since the interval of capturing TSF
1210 * (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC) is long enough, host and target
1211 * time are updated in pairs, and one by one, we can return here to
1212 * avoid requiring spin lock, and to speed up the IRQ processing.
1213 */
1214 if (host_time > 0)
1215 adapter->cur_host_time = host_time;
1216
1217 qdf_spin_lock_bh(&adapter->host_target_sync_lock);
1218 if (target_time > 0)
1219 adapter->cur_target_time = target_time;
1220
1221 sync_status = hdd_check_timestamp_status(adapter->last_target_time,
1222 adapter->last_host_time,
1223 adapter->cur_target_time,
1224 adapter->cur_host_time);
1225 hdd_info("sync_status %d", sync_status);
1226 switch (sync_status) {
1227 case HDD_TS_STATUS_INVALID:
1228 if (++adapter->continuous_error_count <
1229 MAX_CONTINUOUS_ERROR_CNT) {
1230 interval =
1231 WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS;
1232 adapter->cur_target_time = 0;
1233 adapter->cur_host_time = 0;
1234 break;
1235 }
1236 hdd_warn("Reach the max continuous error count");
1237 /*
1238 * fall through:
1239 * If reach MAX_CONTINUOUS_ERROR_CNT, treat it as a
1240 * valid pair
1241 */
1242 case HDD_TS_STATUS_READY:
1243 adapter->last_target_time = adapter->cur_target_time;
1244 adapter->last_host_time = adapter->cur_host_time;
1245 adapter->cur_target_time = 0;
1246 adapter->cur_host_time = 0;
1247 hdd_info("ts-pair updated: target: %llu; host: %llu",
1248 adapter->last_target_time,
1249 adapter->last_host_time);
1250
1251 /*
1252 * TSF-HOST need to be updated in at most
1253 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, it couldn't be achieved
1254 * if the timer interval is also
1255 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, due to processing or
1256 * schedule delay. So deduct several seconds from
1257 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC.
1258 * Without this change, hdd_get_hosttime_from_targettime() will
1259 * get wrong host time when it's longer than
1260 * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last
1261 * TSF-HOST update.
1262 */
1263 interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC -
1264 CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC;
1265 if (adapter->device_mode == QDF_SAP_MODE ||
1266 adapter->device_mode == QDF_P2P_GO_MODE) {
Subrat Dashf75d3d32019-08-23 22:27:37 +05301267 interval *= WLAN_HDD_SOFTAP_INTERVAL_TIMES;
yuanl69575bb2019-01-24 19:16:28 +08001268 }
1269
1270 adapter->continuous_error_count = 0;
Subrat Dash42155f62019-11-21 18:10:21 +05301271 adapter->continuous_cap_retry_count = 0;
yuanl69575bb2019-01-24 19:16:28 +08001272 hdd_debug("ts-pair updated: interval: %d",
1273 interval);
1274 break;
1275 case HDD_TS_STATUS_WAITING:
1276 interval = 0;
1277 hdd_warn("TS status is waiting due to one or more pair not updated");
Subrat Dash42155f62019-11-21 18:10:21 +05301278
1279 if (!target_time && !host_time)
1280 interval = hdd_wlan_retry_tsf_cap(adapter);
yuanl69575bb2019-01-24 19:16:28 +08001281 break;
1282 }
1283 qdf_spin_unlock_bh(&adapter->host_target_sync_lock);
1284
1285 if (interval > 0)
1286 qdf_mc_timer_start(&adapter->host_target_sync_timer, interval);
1287}
1288
1289static ssize_t __hdd_wlan_tsf_show(struct device *dev,
1290 struct device_attribute *attr, char *buf)
1291{
1292 struct hdd_station_ctx *hdd_sta_ctx;
1293 struct hdd_adapter *adapter;
1294 struct hdd_context *hdd_ctx;
1295 ssize_t size;
1296 uint64_t host_time, target_time;
1297
1298 struct net_device *net_dev = container_of(dev, struct net_device, dev);
1299
1300 adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
1301 if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC)
1302 return scnprintf(buf, PAGE_SIZE, "Invalid device\n");
1303
1304 if (!hdd_get_th_sync_status(adapter))
1305 return scnprintf(buf, PAGE_SIZE,
1306 "TSF sync is not initialized\n");
1307
1308 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Jeff Johnsone7951512019-02-27 10:02:51 -08001309 if (eConnectionState_Associated != hdd_sta_ctx->conn_info.conn_state &&
yuanl69575bb2019-01-24 19:16:28 +08001310 (adapter->device_mode == QDF_STA_MODE ||
1311 adapter->device_mode == QDF_P2P_CLIENT_MODE))
1312 return scnprintf(buf, PAGE_SIZE, "NOT connected\n");
1313
1314 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1315 if (!hdd_ctx)
1316 return scnprintf(buf, PAGE_SIZE, "Invalid HDD context\n");
1317
1318 host_time = hdd_get_monotonic_host_time(hdd_ctx);
1319
1320 if (hdd_get_targettime_from_hosttime(adapter, host_time,
1321 &target_time)) {
1322 size = scnprintf(buf, PAGE_SIZE, "Invalid timestamp\n");
1323 } else {
1324 if (adapter->device_mode == QDF_STA_MODE ||
1325 adapter->device_mode == QDF_P2P_CLIENT_MODE) {
1326 size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM\n",
1327 buf, target_time, host_time,
Jeff Johnsone04b6992019-02-27 14:06:55 -08001328 hdd_sta_ctx->conn_info.bssid.bytes);
yuanl69575bb2019-01-24 19:16:28 +08001329 } else {
1330 size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM\n",
1331 buf, target_time, host_time,
1332 adapter->mac_addr.bytes);
1333 }
1334 }
1335
1336 return size;
1337}
1338
1339static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
1340{
1341 uint32_t tsf_op_resp[3];
1342
1343 hdd_indicate_tsf_internal(adapter, tsf_op_resp, 3);
1344 hdd_update_timestamp(adapter, tsf, 0);
1345}
1346#endif
1347
1348static ssize_t hdd_wlan_tsf_show(struct device *dev,
1349 struct device_attribute *attr, char *buf)
1350{
Dustin Brown96b98dd2019-03-06 12:39:37 -08001351 struct net_device *net_dev = container_of(dev, struct net_device, dev);
1352 struct osif_vdev_sync *vdev_sync;
1353 ssize_t err_size;
yuanl69575bb2019-01-24 19:16:28 +08001354
Dustin Brown96b98dd2019-03-06 12:39:37 -08001355 err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
1356 if (err_size)
1357 return err_size;
yuanl69575bb2019-01-24 19:16:28 +08001358
Dustin Brown96b98dd2019-03-06 12:39:37 -08001359 err_size = __hdd_wlan_tsf_show(dev, attr, buf);
1360
1361 osif_vdev_sync_op_stop(vdev_sync);
1362
1363 return err_size;
yuanl69575bb2019-01-24 19:16:28 +08001364}
1365
1366static DEVICE_ATTR(tsf, 0400, hdd_wlan_tsf_show, NULL);
1367
Jeff Johnson8f389862017-08-29 14:19:23 -07001368static enum hdd_tsf_op_result hdd_tsf_sync_init(struct hdd_adapter *adapter)
Yu Wang000dc2f2017-05-26 17:38:48 +08001369{
1370 QDF_STATUS ret;
Jeff Johnson854cccd2017-08-28 11:39:24 -07001371 struct hdd_context *hddctx;
Yu Wang0ea10172017-06-02 13:40:52 +08001372 struct net_device *net_dev;
Yu Wang000dc2f2017-05-26 17:38:48 +08001373
1374 if (!adapter)
1375 return HDD_TSF_OP_FAIL;
1376
1377 hddctx = WLAN_HDD_GET_CTX(adapter);
1378 if (!hddctx) {
1379 hdd_err("invalid hdd context");
1380 return HDD_TSF_OP_FAIL;
1381 }
1382
1383 if (!qdf_atomic_read(&hddctx->tsf_ready_flag)) {
1384 hdd_err("TSF feature has NOT been initialized");
1385 return HDD_TSF_OP_FAIL;
1386 }
1387
1388 if (hdd_get_th_sync_status(adapter)) {
1389 hdd_err("Host Target sync has been initialized!!");
1390 return HDD_TSF_OP_SUCC;
1391 }
1392
1393 qdf_spinlock_create(&adapter->host_target_sync_lock);
1394
1395 hdd_reset_timestamps(adapter);
1396
1397 ret = qdf_mc_timer_init(&adapter->host_target_sync_timer,
1398 QDF_TIMER_TYPE_SW,
1399 hdd_capture_tsf_timer_expired_handler,
1400 (void *)adapter);
1401 if (ret != QDF_STATUS_SUCCESS) {
1402 hdd_err("Failed to init timer, ret: %d", ret);
1403 goto fail;
1404 }
1405
Yu Wang0ea10172017-06-02 13:40:52 +08001406 net_dev = adapter->dev;
yuanl2746f072018-09-21 19:19:16 +08001407 if (net_dev && hdd_tsf_is_dbg_fs_set(hddctx))
Yu Wang66a250b2017-07-19 11:46:40 +08001408 device_create_file(&net_dev->dev, &dev_attr_tsf);
Yu Wang000dc2f2017-05-26 17:38:48 +08001409 hdd_set_th_sync_status(adapter, true);
1410
1411 return HDD_TSF_OP_SUCC;
1412fail:
1413 hdd_set_th_sync_status(adapter, false);
1414 return HDD_TSF_OP_FAIL;
1415}
1416
Jeff Johnson8f389862017-08-29 14:19:23 -07001417static enum hdd_tsf_op_result hdd_tsf_sync_deinit(struct hdd_adapter *adapter)
Yu Wang000dc2f2017-05-26 17:38:48 +08001418{
1419 QDF_STATUS ret;
Jeff Johnson854cccd2017-08-28 11:39:24 -07001420 struct hdd_context *hddctx;
Yu Wang0ea10172017-06-02 13:40:52 +08001421 struct net_device *net_dev;
Yu Wang000dc2f2017-05-26 17:38:48 +08001422
1423 if (!adapter)
1424 return HDD_TSF_OP_FAIL;
1425
1426 if (!hdd_get_th_sync_status(adapter)) {
1427 hdd_err("Host Target sync has not been initialized!!");
1428 return HDD_TSF_OP_SUCC;
1429 }
1430
1431 hdd_set_th_sync_status(adapter, false);
Yu Wang000dc2f2017-05-26 17:38:48 +08001432 ret = qdf_mc_timer_destroy(&adapter->host_target_sync_timer);
1433 if (ret != QDF_STATUS_SUCCESS)
1434 hdd_err("Failed to destroy timer, ret: %d", ret);
1435
1436 hddctx = WLAN_HDD_GET_CTX(adapter);
1437
1438 /* reset the cap_tsf flag and gpio if needed */
1439 if (hddctx && qdf_atomic_read(&hddctx->cap_tsf_flag) &&
1440 hddctx->cap_tsf_context == adapter) {
1441 int reset_ret = hdd_tsf_reset_gpio(adapter);
1442
1443 if (reset_ret)
1444 hdd_err("Failed to reset tsf gpio, ret:%d",
1445 reset_ret);
1446 hddctx->cap_tsf_context = NULL;
1447 qdf_atomic_set(&hddctx->cap_tsf_flag, 0);
1448 }
1449
1450 hdd_reset_timestamps(adapter);
Yu Wang66a250b2017-07-19 11:46:40 +08001451
1452 net_dev = adapter->dev;
yuanl2746f072018-09-21 19:19:16 +08001453 if (net_dev && hdd_tsf_is_dbg_fs_set(hddctx)) {
Yu Wang66a250b2017-07-19 11:46:40 +08001454 struct device *dev = &net_dev->dev;
1455
1456 device_remove_file(dev, &dev_attr_tsf);
1457 }
Yu Wang000dc2f2017-05-26 17:38:48 +08001458 return HDD_TSF_OP_SUCC;
1459}
1460
Jiani Liua8fd1702019-05-01 10:07:10 +08001461#ifdef CONFIG_HL_SUPPORT
Yu Wang04ccd762017-05-31 19:29:43 +08001462static inline
1463enum hdd_tsf_op_result hdd_netbuf_timestamp(qdf_nbuf_t netbuf,
1464 uint64_t target_time)
1465{
Jeff Johnson8f389862017-08-29 14:19:23 -07001466 struct hdd_adapter *adapter;
Yu Wang04ccd762017-05-31 19:29:43 +08001467 struct net_device *net_dev = netbuf->dev;
1468
1469 if (!net_dev)
1470 return HDD_TSF_OP_FAIL;
1471
Jeff Johnson8f389862017-08-29 14:19:23 -07001472 adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
Yu Wang04ccd762017-05-31 19:29:43 +08001473 if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC &&
1474 hdd_get_th_sync_status(adapter)) {
1475 uint64_t host_time;
1476 int32_t ret = hdd_get_hosttime_from_targettime(adapter,
1477 target_time, &host_time);
1478 if (!ret) {
1479 netbuf->tstamp = ns_to_ktime(host_time);
1480 return HDD_TSF_OP_SUCC;
1481 }
1482 }
1483
1484 return HDD_TSF_OP_FAIL;
1485}
1486
Jiani Liua8fd1702019-05-01 10:07:10 +08001487#else
1488static inline
1489enum hdd_tsf_op_result hdd_netbuf_timestamp(qdf_nbuf_t netbuf,
1490 uint64_t target_time)
1491{
1492 struct hdd_adapter *adapter;
1493 struct net_device *net_dev = netbuf->dev;
guangde44f9ab72019-10-17 18:48:44 +08001494 struct skb_shared_hwtstamps hwtstamps;
Jiani Liua8fd1702019-05-01 10:07:10 +08001495
1496 if (!net_dev)
1497 return HDD_TSF_OP_FAIL;
1498
1499 adapter = (struct hdd_adapter *)(netdev_priv(net_dev));
1500 if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC &&
1501 hdd_get_th_sync_status(adapter)) {
1502 uint64_t tsf64_time = target_time;
1503 uint64_t soc_time = 0;/*ns*/
1504 int32_t ret = hdd_get_soctime_from_tsf64time(adapter,
1505 tsf64_time, &soc_time);
1506 if (!ret) {
guangde44f9ab72019-10-17 18:48:44 +08001507 hwtstamps.hwtstamp = soc_time;
1508 *skb_hwtstamps(netbuf) = hwtstamps;
guangde7bd92e62019-10-21 16:46:38 +08001509 netbuf->tstamp = ktime_set(0, 0);
Jiani Liua8fd1702019-05-01 10:07:10 +08001510 return HDD_TSF_OP_SUCC;
1511 }
1512 }
1513
1514 return HDD_TSF_OP_FAIL;
1515}
1516#endif
1517
Jeff Johnson8f389862017-08-29 14:19:23 -07001518int hdd_start_tsf_sync(struct hdd_adapter *adapter)
Yu Wang000dc2f2017-05-26 17:38:48 +08001519{
1520 enum hdd_tsf_op_result ret;
1521
1522 if (!adapter)
1523 return -EINVAL;
1524
1525 ret = hdd_tsf_sync_init(adapter);
1526 if (ret != HDD_TSF_OP_SUCC) {
1527 hdd_err("Failed to init tsf sync, ret: %d", ret);
1528 return -EINVAL;
1529 }
1530
1531 return (__hdd_start_tsf_sync(adapter) ==
1532 HDD_TSF_OP_SUCC) ? 0 : -EINVAL;
1533}
1534
Jeff Johnson8f389862017-08-29 14:19:23 -07001535int hdd_stop_tsf_sync(struct hdd_adapter *adapter)
Yu Wang000dc2f2017-05-26 17:38:48 +08001536{
1537 enum hdd_tsf_op_result ret;
1538
1539 if (!adapter)
1540 return -EINVAL;
1541
1542 ret = __hdd_stop_tsf_sync(adapter);
1543 if (ret != HDD_TSF_OP_SUCC)
1544 return -EINVAL;
1545
1546 ret = hdd_tsf_sync_deinit(adapter);
1547 if (ret != HDD_TSF_OP_SUCC) {
1548 hdd_err("Failed to deinit tsf sync, ret: %d", ret);
1549 return -EINVAL;
1550 }
1551 return 0;
1552}
1553
Yu Wang04ccd762017-05-31 19:29:43 +08001554int hdd_tx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time)
1555{
1556 struct sock *sk = netbuf->sk;
1557
1558 if (!sk)
1559 return -EINVAL;
1560
guangde44f9ab72019-10-17 18:48:44 +08001561 if ((skb_shinfo(netbuf)->tx_flags & SKBTX_HW_TSTAMP) &&
Yu Wang04ccd762017-05-31 19:29:43 +08001562 !(skb_shinfo(netbuf)->tx_flags & SKBTX_IN_PROGRESS)) {
1563 struct sock_exterr_skb *serr;
1564 qdf_nbuf_t new_netbuf;
1565 int err;
1566
1567 if (hdd_netbuf_timestamp(netbuf, target_time) !=
1568 HDD_TSF_OP_SUCC)
1569 return -EINVAL;
1570
1571 new_netbuf = qdf_nbuf_clone(netbuf);
1572 if (!new_netbuf)
1573 return -ENOMEM;
1574
1575 serr = SKB_EXT_ERR(new_netbuf);
1576 memset(serr, 0, sizeof(*serr));
1577 serr->ee.ee_errno = ENOMSG;
1578 serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
1579
1580 err = sock_queue_err_skb(sk, new_netbuf);
1581 if (err) {
1582 qdf_nbuf_free(new_netbuf);
1583 return err;
1584 }
1585
1586 return 0;
1587 }
1588 return -EINVAL;
1589}
1590
1591int hdd_rx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time)
1592{
1593 if (hdd_netbuf_timestamp(netbuf, target_time) ==
1594 HDD_TSF_OP_SUCC)
1595 return 0;
1596
1597 /* reset tstamp when failed */
guangde7bd92e62019-10-21 16:46:38 +08001598 netbuf->tstamp = ktime_set(0, 0);
Yu Wang04ccd762017-05-31 19:29:43 +08001599 return -EINVAL;
1600}
1601
Jeff Johnson8f389862017-08-29 14:19:23 -07001602static inline int __hdd_capture_tsf(struct hdd_adapter *adapter,
Yu Wang000dc2f2017-05-26 17:38:48 +08001603 uint32_t *buf, int len)
1604{
1605 if (!adapter || !buf) {
1606 hdd_err("invalid pointer");
1607 return -EINVAL;
1608 }
1609
1610 if (len != 1)
1611 return -EINVAL;
1612
1613 buf[0] = TSF_DISABLED_BY_TSFPLUS;
1614
1615 return 0;
1616}
1617
Jeff Johnson8f389862017-08-29 14:19:23 -07001618static inline int __hdd_indicate_tsf(struct hdd_adapter *adapter,
Yu Wang000dc2f2017-05-26 17:38:48 +08001619 uint32_t *buf, int len)
1620{
1621 if (!adapter || !buf) {
1622 hdd_err("invalid pointer");
1623 return -EINVAL;
1624 }
1625
1626 if (len != 3)
1627 return -EINVAL;
1628
1629 buf[0] = TSF_DISABLED_BY_TSFPLUS;
1630 buf[1] = 0;
1631 buf[2] = 0;
1632
1633 return 0;
1634}
1635
Subrat Dashb1e61b22019-07-22 14:09:34 +05301636#if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ)
yuanl2746f072018-09-21 19:19:16 +08001637static inline
1638enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
1639{
yuanl2746f072018-09-21 19:19:16 +08001640
1641 if (hdd_tsf_is_tx_set(hdd_ctx))
1642 ol_register_timestamp_callback(hdd_tx_timestamp);
1643 return HDD_TSF_OP_SUCC;
1644}
1645
1646static inline
1647enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
1648{
1649 QDF_STATUS status;
1650 QDF_TIMER_STATE capture_req_timer_status;
1651 qdf_mc_timer_t *cap_timer;
1652 struct hdd_adapter *adapter, *adapternode_ptr, *next_ptr;
1653
yuanl2746f072018-09-21 19:19:16 +08001654 if (hdd_tsf_is_tx_set(hdd_ctx))
1655 ol_deregister_timestamp_callback();
1656
1657 status = hdd_get_front_adapter(hdd_ctx, &adapternode_ptr);
1658
Jeff Johnsond36fa332019-03-18 13:42:25 -07001659 while (adapternode_ptr && QDF_STATUS_SUCCESS == status) {
yuanl2746f072018-09-21 19:19:16 +08001660 adapter = adapternode_ptr;
1661 status =
1662 hdd_get_next_adapter(hdd_ctx, adapternode_ptr, &next_ptr);
1663 adapternode_ptr = next_ptr;
1664 if (adapter->host_capture_req_timer.state == 0)
1665 continue;
1666 cap_timer = &adapter->host_capture_req_timer;
1667 capture_req_timer_status =
1668 qdf_mc_timer_get_current_state(cap_timer);
1669
1670 if (capture_req_timer_status != QDF_TIMER_STATE_UNUSED) {
1671 qdf_mc_timer_stop(cap_timer);
1672 status =
1673 qdf_mc_timer_destroy(cap_timer);
1674 if (status != QDF_STATUS_SUCCESS)
1675 hdd_err("remove timer failed: %d", status);
1676 }
1677 }
1678
1679 return HDD_TSF_OP_SUCC;
1680}
Subrat Dashb1e61b22019-07-22 14:09:34 +05301681
1682#elif defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC)
1683static
1684enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
1685{
1686 int ret;
1687 QDF_STATUS status;
1688 uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID;
1689
1690 status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc,
1691 &tsf_sync_gpio_pin);
1692 if (QDF_IS_STATUS_ERROR(status)) {
1693 hdd_err("tsf gpio irq host pin error");
1694 goto fail;
1695 }
1696
1697 if (tsf_sync_gpio_pin == TSF_GPIO_PIN_INVALID) {
1698 hdd_err("gpio host pin is invalid");
1699 goto fail;
1700 }
1701
1702 ret = gpio_request(tsf_sync_gpio_pin, "wlan_tsf");
1703 if (ret) {
1704 hdd_err("gpio host pin is invalid");
1705 goto fail;
1706 }
1707
1708 ret = gpio_direction_output(tsf_sync_gpio_pin, OUTPUT_LOW);
1709 if (ret) {
1710 hdd_err("gpio host pin is invalid");
1711 goto fail_free_gpio;
1712 }
1713
1714 if (hdd_tsf_is_tx_set(hdd_ctx))
1715 ol_register_timestamp_callback(hdd_tx_timestamp);
1716
1717 return HDD_TSF_OP_SUCC;
1718
1719fail_free_gpio:
1720 gpio_free(tsf_sync_gpio_pin);
1721fail:
1722 return HDD_TSF_OP_FAIL;
1723}
1724
1725static
1726enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
1727{
1728 QDF_STATUS status;
1729 uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID;
1730
1731 status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc,
1732 &tsf_sync_gpio_pin);
1733 if (QDF_IS_STATUS_ERROR(status))
1734 return QDF_STATUS_E_INVAL;
1735
1736 if (tsf_sync_gpio_pin == TSF_GPIO_PIN_INVALID)
1737 return QDF_STATUS_E_INVAL;
1738
1739 if (hdd_tsf_is_tx_set(hdd_ctx))
1740 ol_deregister_timestamp_callback();
1741
1742 gpio_free(tsf_sync_gpio_pin);
1743 return HDD_TSF_OP_SUCC;
1744}
1745
1746#elif defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ)
Subrat Dash5f36fbe2019-02-12 16:28:14 +05301747static
1748enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
1749{
1750 int ret;
1751 QDF_STATUS status;
1752 uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID;
1753
Subrat Dash5f36fbe2019-02-12 16:28:14 +05301754 status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc,
1755 &tsf_irq_gpio_pin);
1756 if (QDF_IS_STATUS_ERROR(status)) {
1757 hdd_err("tsf gpio irq host pin error");
1758 goto fail;
1759 }
1760
1761 if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID) {
1762 hdd_err("gpio host pin is invalid");
1763 goto fail;
1764 }
1765
1766 ret = gpio_request(tsf_irq_gpio_pin, "wlan_tsf");
1767 if (ret) {
1768 hdd_err("gpio host pin is invalid");
1769 goto fail;
1770 }
1771
1772 ret = gpio_direction_input(tsf_irq_gpio_pin);
1773 if (ret) {
1774 hdd_err("gpio host pin is invalid");
1775 goto fail_free_gpio;
1776 }
1777
1778 tsf_gpio_irq_num = gpio_to_irq(tsf_irq_gpio_pin);
1779 if (tsf_gpio_irq_num < 0) {
1780 hdd_err("fail to get irq: %d", tsf_gpio_irq_num);
1781 goto fail_free_gpio;
1782 }
1783
1784 ret = request_irq(tsf_gpio_irq_num, hdd_tsf_captured_irq_handler,
1785 IRQF_SHARED | IRQF_TRIGGER_RISING, "wlan_tsf",
1786 hdd_ctx);
1787
1788 if (ret) {
1789 hdd_err("Failed to register irq handler: %d", ret);
1790 goto fail_free_gpio;
1791 }
1792
1793 if (hdd_tsf_is_tx_set(hdd_ctx))
1794 ol_register_timestamp_callback(hdd_tx_timestamp);
1795
1796 return HDD_TSF_OP_SUCC;
1797
1798fail_free_gpio:
1799 gpio_free(tsf_irq_gpio_pin);
1800fail:
1801 tsf_gpio_irq_num = -1;
1802 return HDD_TSF_OP_FAIL;
1803}
1804
1805static
1806enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
1807{
1808 QDF_STATUS status;
1809 uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID;
1810
Subrat Dash5f36fbe2019-02-12 16:28:14 +05301811 status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc,
1812 &tsf_irq_gpio_pin);
1813 if (QDF_IS_STATUS_ERROR(status))
1814 return QDF_STATUS_E_INVAL;
1815
1816 if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID)
1817 return QDF_STATUS_E_INVAL;
1818
1819 if (hdd_tsf_is_tx_set(hdd_ctx))
1820 ol_deregister_timestamp_callback();
1821
1822 if (tsf_gpio_irq_num >= 0) {
1823 free_irq(tsf_gpio_irq_num, hdd_ctx);
1824 tsf_gpio_irq_num = -1;
1825 gpio_free(tsf_irq_gpio_pin);
1826 }
1827
1828 return HDD_TSF_OP_SUCC;
1829}
Subrat Dashb1e61b22019-07-22 14:09:34 +05301830
Paul Zhangfaa929c2019-11-12 10:10:44 +08001831#elif defined(WLAN_FEATURE_TSF_TIMER_SYNC)
1832static inline
1833enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
1834{
1835 return HDD_TSF_OP_SUCC;
1836}
1837
1838static inline
1839enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
1840{
1841 return HDD_TSF_OP_SUCC;
1842}
Subrat Dash5f36fbe2019-02-12 16:28:14 +05301843#else
Yu Wang000dc2f2017-05-26 17:38:48 +08001844static inline
Jeff Johnson854cccd2017-08-28 11:39:24 -07001845enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
Yu Wang000dc2f2017-05-26 17:38:48 +08001846{
1847 int ret;
1848
1849 ret = cnss_common_register_tsf_captured_handler(
1850 hdd_ctx->parent_dev,
1851 hdd_tsf_captured_irq_handler,
1852 (void *)hdd_ctx);
1853 if (ret != 0) {
1854 hdd_err("Failed to register irq handler: %d", ret);
1855 return HDD_TSF_OP_FAIL;
1856 }
Yu Wangceb357b2017-06-01 12:04:18 +08001857
yuanl2746f072018-09-21 19:19:16 +08001858 if (hdd_tsf_is_tx_set(hdd_ctx))
Yu Wang66a250b2017-07-19 11:46:40 +08001859 ol_register_timestamp_callback(hdd_tx_timestamp);
Yu Wang000dc2f2017-05-26 17:38:48 +08001860 return HDD_TSF_OP_SUCC;
1861}
1862
1863static inline
Jeff Johnson854cccd2017-08-28 11:39:24 -07001864enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
Yu Wang000dc2f2017-05-26 17:38:48 +08001865{
1866 int ret;
1867
yuanl2746f072018-09-21 19:19:16 +08001868 if (hdd_tsf_is_tx_set(hdd_ctx))
Yu Wang66a250b2017-07-19 11:46:40 +08001869 ol_deregister_timestamp_callback();
1870
Yu Wang000dc2f2017-05-26 17:38:48 +08001871 ret = cnss_common_unregister_tsf_captured_handler(
1872 hdd_ctx->parent_dev,
1873 (void *)hdd_ctx);
1874 if (ret != 0) {
1875 hdd_err("Failed to unregister irq handler, ret:%d",
1876 ret);
1877 ret = HDD_TSF_OP_FAIL;
1878 }
1879
1880 return HDD_TSF_OP_SUCC;
1881}
yuanl2746f072018-09-21 19:19:16 +08001882#endif
Yu Wang000dc2f2017-05-26 17:38:48 +08001883
Jeff Johnson8f389862017-08-29 14:19:23 -07001884void hdd_tsf_notify_wlan_state_change(struct hdd_adapter *adapter,
Yu Wang000dc2f2017-05-26 17:38:48 +08001885 eConnectionState old_state,
1886 eConnectionState new_state)
1887{
1888 if (!adapter)
1889 return;
1890
1891 if (old_state != eConnectionState_Associated &&
1892 new_state == eConnectionState_Associated)
1893 hdd_start_tsf_sync(adapter);
1894 else if (old_state == eConnectionState_Associated &&
1895 new_state != eConnectionState_Associated)
1896 hdd_stop_tsf_sync(adapter);
1897}
1898#else
Jeff Johnson8f389862017-08-29 14:19:23 -07001899static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf)
Yu Wang000dc2f2017-05-26 17:38:48 +08001900{
1901}
1902
Jeff Johnson8f389862017-08-29 14:19:23 -07001903static inline int __hdd_indicate_tsf(struct hdd_adapter *adapter,
Yu Wang000dc2f2017-05-26 17:38:48 +08001904 uint32_t *buf, int len)
1905{
1906 return (hdd_indicate_tsf_internal(adapter, buf, len) ==
1907 HDD_TSF_OP_SUCC) ? 0 : -EINVAL;
1908}
1909
Jeff Johnson8f389862017-08-29 14:19:23 -07001910static inline int __hdd_capture_tsf(struct hdd_adapter *adapter,
Yu Wang000dc2f2017-05-26 17:38:48 +08001911 uint32_t *buf, int len)
Yu Wangf5d5b5f2017-05-25 22:38:32 +08001912{
1913 return (hdd_capture_tsf_internal(adapter, buf, len) ==
1914 HDD_TSF_OP_SUCC) ? 0 : -EINVAL;
1915}
1916
Yu Wang000dc2f2017-05-26 17:38:48 +08001917static inline
Jeff Johnson854cccd2017-08-28 11:39:24 -07001918enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
Yu Wang000dc2f2017-05-26 17:38:48 +08001919{
1920 return HDD_TSF_OP_SUCC;
1921}
1922
1923static inline
Jeff Johnson854cccd2017-08-28 11:39:24 -07001924enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
Yu Wang000dc2f2017-05-26 17:38:48 +08001925{
1926 return HDD_TSF_OP_SUCC;
1927}
1928#endif /* WLAN_FEATURE_TSF_PLUS */
1929
Jeff Johnson8f389862017-08-29 14:19:23 -07001930int hdd_capture_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len)
Yu Wang000dc2f2017-05-26 17:38:48 +08001931{
1932 return __hdd_capture_tsf(adapter, buf, len);
1933}
1934
Jeff Johnson8f389862017-08-29 14:19:23 -07001935int hdd_indicate_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len)
Yu Wangf5d5b5f2017-05-25 22:38:32 +08001936{
Yu Wang000dc2f2017-05-26 17:38:48 +08001937 return __hdd_indicate_tsf(adapter, buf, len);
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07001938}
1939
Subrat Dash5f36fbe2019-02-12 16:28:14 +05301940#ifdef WLAN_FEATURE_TSF_PTP
1941int wlan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
1942
1943{
1944 struct hdd_adapter *adapter = netdev_priv(dev);
1945 struct osif_vdev_sync *vdev_sync;
1946 struct hdd_context *hdd_ctx;
1947 int errno;
1948
1949 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1950 errno = wlan_hdd_validate_context(hdd_ctx);
1951 if (errno)
1952 return -EINVAL;
1953
1954 errno = osif_vdev_sync_op_start(dev, &vdev_sync);
1955 if (errno)
1956 return -EAGAIN;
1957
1958 info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
1959 SOF_TIMESTAMPING_RX_HARDWARE |
1960 SOF_TIMESTAMPING_RAW_HARDWARE;
1961 if (hdd_ctx->ptp_clock)
1962 info->phc_index = ptp_clock_index(hdd_ctx->ptp_clock);
1963 else
1964 info->phc_index = -1;
1965
1966 osif_vdev_sync_op_stop(vdev_sync);
1967 return 0;
1968}
1969
1970#if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE)
1971/**
1972 * wlan_ptp_gettime() - return fw ts info to uplayer
1973 * @ptp: pointer to ptp_clock_info.
1974 * @ts: pointer to timespec.
1975 *
1976 * Return: Describe the execute result of this routine
1977 */
1978static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
1979{
1980 uint64_t host_time, target_time = 0;
1981 struct hdd_context *hdd_ctx;
1982 struct hdd_adapter *adapter;
1983 uint32_t tsf_reg_read_enabled;
1984 struct osif_psoc_sync *psoc_sync;
1985 int errno, status = 0;
1986
1987 hdd_ctx = qdf_container_of(ptp, struct hdd_context, ptp_cinfo);
1988 errno = wlan_hdd_validate_context(hdd_ctx);
1989 if (errno)
1990 return -EINVAL;
1991
1992 errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync);
1993 if (errno)
1994 return -EAGAIN;
1995
1996 adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE);
1997 if (!adapter) {
1998 adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE);
1999 if (!adapter) {
2000 adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
2001 if (!adapter)
2002 adapter = hdd_get_adapter(hdd_ctx,
2003 QDF_STA_MODE);
2004 if (!adapter) {
2005 status = -EOPNOTSUPP;
2006 goto end;
2007 }
2008 }
2009 }
2010
2011 host_time = hdd_get_monotonic_host_time(hdd_ctx);
2012 if (hdd_get_targettime_from_hosttime(adapter, host_time,
2013 &target_time)) {
2014 hdd_err("get invalid target timestamp");
2015 status = -EINVAL;
2016 goto end;
2017 }
2018 *ts = ns_to_timespec(target_time * NSEC_PER_USEC);
2019
2020end:
2021 osif_psoc_sync_op_stop(psoc_sync);
2022 return status;
2023}
2024
2025/**
2026 * wlan_hdd_phc_init() - phc init
2027 * @hdd_ctx: pointer to the hdd_contex.
2028 *
2029 * Return: NULL
2030 */
2031static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
2032{
2033 hdd_ctx->ptp_cinfo.gettime = wlan_ptp_gettime;
2034
2035 hdd_ctx->ptp_clock = ptp_clock_register(&hdd_ctx->ptp_cinfo,
2036 hdd_ctx->parent_dev);
2037}
2038
2039/**
2040 * wlan_hdd_phc_deinit() - phc deinit
2041 * @hdd_ctx: pointer to the hdd_contex.
2042 *
2043 * Return: NULL
2044 */
2045static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
2046{
2047 hdd_ctx->ptp_cinfo.gettime = NULL;
2048
2049 if (hdd_ctx->ptp_clock) {
2050 ptp_clock_unregister(hdd_ctx->ptp_clock);
2051 hdd_ctx->ptp_clock = NULL;
2052 }
2053}
2054
2055#else
2056static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
2057{
2058 uint64_t host_time, target_time = 0;
2059 struct hdd_context *hdd_ctx;
2060 struct hdd_adapter *adapter;
2061 struct osif_psoc_sync *psoc_sync;
2062 int errno, status = 0;
2063
2064 hdd_ctx = qdf_container_of(ptp, struct hdd_context, ptp_cinfo);
2065 errno = wlan_hdd_validate_context(hdd_ctx);
2066 if (errno)
2067 return -EINVAL;
2068
2069 errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync);
2070 if (errno)
2071 return -EAGAIN;
2072
2073 adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE);
2074 if (!adapter) {
2075 adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE);
2076 if (!adapter) {
2077 adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
2078 if (!adapter)
2079 adapter = hdd_get_adapter(hdd_ctx,
2080 QDF_STA_MODE);
2081 if (!adapter) {
2082 status = -EOPNOTSUPP;
2083 goto end;
2084 }
2085 }
2086 }
2087
2088 host_time = hdd_get_monotonic_host_time(hdd_ctx);
2089 if (hdd_get_targettime_from_hosttime(adapter, host_time,
2090 &target_time)) {
2091 hdd_err("get invalid target timestamp");
2092 status = -EINVAL;
2093 goto end;
2094 }
2095 *ts = ns_to_timespec64(target_time * NSEC_PER_USEC);
2096
2097end:
2098 osif_psoc_sync_op_stop(psoc_sync);
2099 return status;
2100}
2101
2102static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
2103{
2104 hdd_ctx->ptp_cinfo.gettime64 = wlan_ptp_gettime;
2105 hdd_ctx->ptp_clock = ptp_clock_register(&hdd_ctx->ptp_cinfo,
2106 hdd_ctx->parent_dev);
2107}
2108
2109static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
2110{
2111 hdd_ctx->ptp_cinfo.gettime64 = NULL;
2112
2113 if (hdd_ctx->ptp_clock) {
2114 ptp_clock_unregister(hdd_ctx->ptp_clock);
2115 hdd_ctx->ptp_clock = NULL;
2116 }
2117}
2118
2119#endif
2120#else
2121
2122static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
2123{
2124}
2125
2126static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
2127{
2128}
2129#endif /* WLAN_FEATURE_TSF_PTP */
2130
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002131/**
2132 * hdd_get_tsf_cb() - handle tsf callback
2133 * @pcb_cxt: pointer to the hdd_contex
2134 * @ptsf: pointer to struct stsf
2135 *
2136 * This function handle the event that reported by firmware at first.
2137 * The event contains the vdev_id, current tsf value of this vdev,
2138 * tsf value is 64bits, discripted in two varaible tsf_low and tsf_high.
2139 * These two values each is uint32.
2140 *
2141 * Return: 0 for success or non-zero negative failure code
2142 */
Arun Khandavalli4b55da72016-07-19 19:55:01 +05302143int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf)
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002144{
Jeff Johnson82797b62017-08-11 15:31:27 -07002145 struct hdd_context *hddctx;
Jeff Johnson85b5c112017-08-11 15:15:23 -07002146 struct hdd_adapter *adapter;
yuanl2746f072018-09-21 19:19:16 +08002147 int ret;
yuanl69575bb2019-01-24 19:16:28 +08002148 uint64_t tsf_sync_soc_time;
yuanl2746f072018-09-21 19:19:16 +08002149 QDF_STATUS status;
2150 QDF_TIMER_STATE capture_req_timer_status;
2151 qdf_mc_timer_t *capture_timer;
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002152
Jeff Johnsond36fa332019-03-18 13:42:25 -07002153 if (!pcb_cxt || !ptsf) {
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002154 hdd_err("HDD context is not valid");
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002155 return -EINVAL;
2156 }
2157
Jeff Johnson82797b62017-08-11 15:31:27 -07002158 hddctx = (struct hdd_context *)pcb_cxt;
yuanl2746f072018-09-21 19:19:16 +08002159 ret = wlan_hdd_validate_context(hddctx);
2160 if (0 != ret)
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002161 return -EINVAL;
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002162
2163 adapter = hdd_get_adapter_by_vdev(hddctx, ptsf->vdev_id);
2164
Jeff Johnsond36fa332019-03-18 13:42:25 -07002165 if (!adapter) {
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002166 hdd_err("failed to find adapter");
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002167 return -EINVAL;
2168 }
Yu Wangf5d5b5f2017-05-25 22:38:32 +08002169
2170 if (!hdd_tsf_is_initialized(adapter)) {
2171 hdd_err("tsf is not init, ignore tsf event");
2172 return -EINVAL;
2173 }
2174
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002175 hdd_info("tsf cb handle event, device_mode is %d",
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002176 adapter->device_mode);
2177
yuanl2746f072018-09-21 19:19:16 +08002178 capture_timer = &adapter->host_capture_req_timer;
2179 capture_req_timer_status =
2180 qdf_mc_timer_get_current_state(capture_timer);
2181 if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) {
2182 hdd_warn("invalid timer status");
2183 return -EINVAL;
2184 }
2185
2186 qdf_mc_timer_stop(capture_timer);
2187 status = qdf_mc_timer_destroy(capture_timer);
2188 if (status != QDF_STATUS_SUCCESS)
2189 hdd_warn("destroy cap req timer fail, ret: %d", status);
2190
Yu Wangf5d5b5f2017-05-25 22:38:32 +08002191 adapter->cur_target_time = ((uint64_t)ptsf->tsf_high << 32 |
2192 ptsf->tsf_low);
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002193
Jiani Liua8fd1702019-05-01 10:07:10 +08002194 adapter->cur_target_global_tsf_time =
2195 ((uint64_t)ptsf->global_tsf_high << 32 |
2196 ptsf->global_tsf_low);
yuanl69575bb2019-01-24 19:16:28 +08002197 tsf_sync_soc_time = ((uint64_t)ptsf->soc_timer_high << 32 |
2198 ptsf->soc_timer_low);
yuanl69575bb2019-01-24 19:16:28 +08002199 adapter->cur_tsf_sync_soc_time =
2200 qdf_log_timestamp_to_usecs(tsf_sync_soc_time) * NSEC_PER_USEC;
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002201 complete(&tsf_sync_get_completion_evt);
Yu Wang000dc2f2017-05-26 17:38:48 +08002202 hdd_update_tsf(adapter, adapter->cur_target_time);
yuanl69575bb2019-01-24 19:16:28 +08002203 hdd_info("Vdev=%u, tsf_low=%u, tsf_high=%u ptsf->soc_timer_low=%u ptsf->soc_timer_high=%u",
2204 ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high,
2205 ptsf->soc_timer_low, ptsf->soc_timer_high);
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002206 return 0;
2207}
2208
Jeff Johnson363764f2017-06-02 13:43:36 -07002209static const struct nla_policy tsf_policy[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1] = {
2210 [QCA_WLAN_VENDOR_ATTR_TSF_CMD] = {.type = NLA_U32},
2211};
2212
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002213/**
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002214 * __wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations
2215 * @wiphy: Pointer to wireless phy
2216 * @wdev: Pointer to wireless device
2217 * @data: Pointer to data
2218 * @data_len: Data length
2219 *
2220 * Handle TSF SET / GET operation from userspace
2221 *
2222 * Return: 0 on success, negative errno on failure
2223 */
2224static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
2225 struct wireless_dev *wdev,
2226 const void *data,
2227 int data_len)
2228{
2229 struct net_device *dev = wdev->netdev;
Jeff Johnson8f389862017-08-29 14:19:23 -07002230 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson854cccd2017-08-28 11:39:24 -07002231 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002232 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1];
2233 int status, ret;
2234 struct sk_buff *reply_skb;
Subrat Dash5f36fbe2019-02-12 16:28:14 +05302235 uint32_t tsf_op_resp[3] = {0}, tsf_cmd;
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002236
Dustin Brownfdf17c12018-03-14 12:55:34 -07002237 hdd_enter_dev(wdev->netdev);
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002238
2239 status = wlan_hdd_validate_context(hdd_ctx);
2240 if (0 != status)
2241 return -EINVAL;
2242
Dustin Brown4ea21db2018-01-05 14:13:17 -08002243 if (wlan_cfg80211_nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TSF_MAX,
2244 data, data_len, tsf_policy)) {
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002245 hdd_err("Invalid TSF cmd");
2246 return -EINVAL;
2247 }
2248
2249 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]) {
2250 hdd_err("Invalid TSF cmd");
2251 return -EINVAL;
2252 }
2253 tsf_cmd = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]);
2254
2255 if (tsf_cmd == QCA_TSF_CAPTURE || tsf_cmd == QCA_TSF_SYNC_GET) {
2256 hdd_capture_tsf(adapter, tsf_op_resp, 1);
2257 switch (tsf_op_resp[0]) {
2258 case TSF_RETURN:
2259 status = 0;
2260 break;
2261 case TSF_CURRENT_IN_CAP_STATE:
2262 status = -EALREADY;
2263 break;
2264 case TSF_STA_NOT_CONNECTED_NO_TSF:
2265 case TSF_SAP_NOT_STARTED_NO_TSF:
2266 status = -EPERM;
2267 break;
2268 default:
2269 case TSF_CAPTURE_FAIL:
2270 status = -EINVAL;
2271 break;
2272 }
2273 }
2274 if (status < 0)
2275 goto end;
2276
2277 if (tsf_cmd == QCA_TSF_SYNC_GET) {
2278 ret = wait_for_completion_timeout(&tsf_sync_get_completion_evt,
2279 msecs_to_jiffies(WLAN_TSF_SYNC_GET_TIMEOUT));
2280 if (ret == 0) {
2281 status = -ETIMEDOUT;
2282 goto end;
2283 }
2284 }
2285
2286 if (tsf_cmd == QCA_TSF_GET || tsf_cmd == QCA_TSF_SYNC_GET) {
2287 hdd_indicate_tsf(adapter, tsf_op_resp, 3);
2288 switch (tsf_op_resp[0]) {
2289 case TSF_RETURN:
2290 status = 0;
2291 break;
2292 case TSF_NOT_RETURNED_BY_FW:
2293 status = -EINPROGRESS;
2294 break;
2295 case TSF_STA_NOT_CONNECTED_NO_TSF:
2296 case TSF_SAP_NOT_STARTED_NO_TSF:
2297 status = -EPERM;
2298 break;
2299 default:
2300 status = -EINVAL;
2301 break;
2302 }
2303 if (status != 0)
2304 goto end;
2305
2306 reply_skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL,
2307 sizeof(uint64_t) * 2 + NLMSG_HDRLEN,
2308 QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX,
2309 GFP_KERNEL);
2310 if (!reply_skb) {
2311 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
2312 status = -ENOMEM;
2313 goto end;
2314 }
Dustin Brownbb7e2f52016-10-17 12:16:35 -07002315 if (hdd_wlan_nla_put_u64(reply_skb,
2316 QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE,
Yu Wangf5d5b5f2017-05-25 22:38:32 +08002317 adapter->cur_target_time) ||
Dustin Brownbb7e2f52016-10-17 12:16:35 -07002318 hdd_wlan_nla_put_u64(reply_skb,
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002319 QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE,
yuanl69575bb2019-01-24 19:16:28 +08002320 adapter->cur_tsf_sync_soc_time)) {
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002321 hdd_err("nla put fail");
2322 kfree_skb(reply_skb);
2323 status = -EINVAL;
2324 goto end;
2325 }
2326 status = cfg80211_vendor_cmd_reply(reply_skb);
2327 }
2328
2329end:
yuanl2746f072018-09-21 19:19:16 +08002330 hdd_info("TSF operation %d status: %d", tsf_cmd, status);
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002331 return status;
2332}
2333
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002334int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy,
2335 struct wireless_dev *wdev,
2336 const void *data,
2337 int data_len)
2338{
Dustin Browna09acf42018-11-08 12:32:26 +05302339 int errno;
2340 struct osif_vdev_sync *vdev_sync;
2341
2342 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
2343 if (errno)
2344 return errno;
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002345
Dustin Browna09acf42018-11-08 12:32:26 +05302346 errno = __wlan_hdd_cfg80211_handle_tsf_cmd(wiphy, wdev, data, data_len);
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002347
Dustin Browna09acf42018-11-08 12:32:26 +05302348 osif_vdev_sync_op_stop(vdev_sync);
2349
2350 return errno;
Manikandan Mohan5356c2b2016-04-03 15:51:35 -07002351}
2352
2353/**
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002354 * wlan_hdd_tsf_init() - set callback to handle tsf value.
Jeff Johnson82797b62017-08-11 15:31:27 -07002355 * @hdd_ctx: pointer to the struct hdd_context
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002356 *
2357 * This function set the callback to sme module, the callback will be
2358 * called when a tsf event is reported by firmware
2359 *
2360 * Return: none
2361 */
Jeff Johnson82797b62017-08-11 15:31:27 -07002362void wlan_hdd_tsf_init(struct hdd_context *hdd_ctx)
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002363{
Jeff Johnsonad278e62018-06-14 11:11:24 -07002364 QDF_STATUS status;
Yu Wangf5d5b5f2017-05-25 22:38:32 +08002365
2366 if (!hdd_ctx)
2367 return;
2368
2369 if (qdf_atomic_inc_return(&hdd_ctx->tsf_ready_flag) > 1)
2370 return;
2371
2372 qdf_atomic_init(&hdd_ctx->cap_tsf_flag);
2373
yuanl2746f072018-09-21 19:19:16 +08002374 status = hdd_tsf_set_gpio(hdd_ctx);
Sourav Mohapatra0f3b8572018-09-12 10:03:51 +05302375
Jeff Johnsonad278e62018-06-14 11:11:24 -07002376 if (QDF_STATUS_SUCCESS != status) {
2377 hdd_err("set tsf GPIO failed, status: %d", status);
Yu Wangf5d5b5f2017-05-25 22:38:32 +08002378 goto fail;
2379 }
2380
Yu Wang000dc2f2017-05-26 17:38:48 +08002381 if (wlan_hdd_tsf_plus_init(hdd_ctx) != HDD_TSF_OP_SUCC)
2382 goto fail;
2383
Subrat Dashb1e61b22019-07-22 14:09:34 +05302384 if (hdd_tsf_is_ptp_enabled(hdd_ctx))
2385 wlan_hdd_phc_init(hdd_ctx);
Subrat Dash5f36fbe2019-02-12 16:28:14 +05302386
Yu Wangf5d5b5f2017-05-25 22:38:32 +08002387 return;
2388
2389fail:
2390 qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0);
2391}
2392
Jeff Johnson854cccd2017-08-28 11:39:24 -07002393void wlan_hdd_tsf_deinit(struct hdd_context *hdd_ctx)
Yu Wangf5d5b5f2017-05-25 22:38:32 +08002394{
2395 if (!hdd_ctx)
2396 return;
2397
2398 if (!qdf_atomic_read(&hdd_ctx->tsf_ready_flag))
2399 return;
2400
Subrat Dashb1e61b22019-07-22 14:09:34 +05302401 if (hdd_tsf_is_ptp_enabled(hdd_ctx))
2402 wlan_hdd_phc_deinit(hdd_ctx);
Yu Wang000dc2f2017-05-26 17:38:48 +08002403 wlan_hdd_tsf_plus_deinit(hdd_ctx);
Yu Wangf5d5b5f2017-05-25 22:38:32 +08002404 qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0);
2405 qdf_atomic_set(&hdd_ctx->cap_tsf_flag, 0);
Manikandan Mohandcc21ba2016-03-15 14:31:56 -07002406}