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