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