1 /*
2 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /**
19 * DOC: Implement various notification handlers which are accessed
20 * internally in ftm_time_sync component only.
21 */
22
23 #include "ftm_time_sync_main.h"
24 #include "target_if_ftm_time_sync.h"
25 #include "wlan_objmgr_vdev_obj.h"
26 #include "cfg_ftm_time_sync.h"
27 #include "cfg_ucfg_api.h"
28 #include <pld_common.h>
29
ftm_time_sync_set_enable(struct wlan_objmgr_psoc * psoc,bool value)30 void ftm_time_sync_set_enable(struct wlan_objmgr_psoc *psoc, bool value)
31 {
32 struct ftm_time_sync_psoc_priv *psoc_priv;
33
34 if (!psoc) {
35 ftm_time_sync_err("psoc is NULL");
36 return;
37 }
38
39 psoc_priv = ftm_time_sync_psoc_get_priv(psoc);
40 if (!psoc_priv) {
41 ftm_time_sync_err("psoc priv is NULL");
42 return;
43 }
44
45 psoc_priv->cfg_param.enable &= value;
46 }
47
ftm_time_sync_is_enable(struct wlan_objmgr_psoc * psoc)48 bool ftm_time_sync_is_enable(struct wlan_objmgr_psoc *psoc)
49 {
50 struct ftm_time_sync_psoc_priv *psoc_priv;
51
52 if (!psoc) {
53 ftm_time_sync_err("psoc is NULL");
54 return false;
55 }
56
57 psoc_priv = ftm_time_sync_psoc_get_priv(psoc);
58 if (!psoc_priv) {
59 ftm_time_sync_err("psoc priv is NULL");
60 return false;
61 }
62
63 return psoc_priv->cfg_param.enable;
64 }
65
ftm_time_sync_get_mode(struct wlan_objmgr_psoc * psoc)66 enum ftm_time_sync_mode ftm_time_sync_get_mode(struct wlan_objmgr_psoc *psoc)
67 {
68 struct ftm_time_sync_psoc_priv *psoc_priv;
69
70 if (!psoc) {
71 ftm_time_sync_err("psoc is NULL");
72 return FTM_TIMESYNC_AGGREGATED_MODE;
73 }
74
75 psoc_priv = ftm_time_sync_psoc_get_priv(psoc);
76 if (!psoc_priv) {
77 ftm_time_sync_err("psoc priv is NULL");
78 return FTM_TIMESYNC_AGGREGATED_MODE;
79 }
80
81 return psoc_priv->cfg_param.mode;
82 }
83
ftm_time_sync_get_role(struct wlan_objmgr_psoc * psoc)84 enum ftm_time_sync_role ftm_time_sync_get_role(struct wlan_objmgr_psoc *psoc)
85 {
86 struct ftm_time_sync_psoc_priv *psoc_priv;
87
88 if (!psoc) {
89 ftm_time_sync_err("psoc is NULL");
90 return FTM_TIMESYNC_TARGET_ROLE;
91 }
92
93 psoc_priv = ftm_time_sync_psoc_get_priv(psoc);
94 if (!psoc_priv) {
95 ftm_time_sync_err("psoc priv is NULL");
96 return FTM_TIMESYNC_TARGET_ROLE;
97 }
98
99 return psoc_priv->cfg_param.role;
100 }
101
ftm_time_sync_work_handler(void * arg)102 static void ftm_time_sync_work_handler(void *arg)
103 {
104 struct ftm_time_sync_vdev_priv *vdev_priv = arg;
105 struct wlan_objmgr_psoc *psoc;
106 qdf_device_t qdf_dev;
107 QDF_STATUS status;
108 uint8_t vdev_id;
109 uint64_t lpass_ts;
110
111 if (!vdev_priv) {
112 ftm_time_sync_err("ftm vdev priv is Null");
113 return;
114 }
115
116 psoc = wlan_vdev_get_psoc(vdev_priv->vdev);
117 if (!psoc) {
118 ftm_time_sync_err("Failed to get psoc");
119 return;
120 }
121
122 vdev_id = wlan_vdev_get_id(vdev_priv->vdev);
123
124 qdf_dev = wlan_psoc_get_qdf_dev(psoc);
125 pld_get_audio_wlan_timestamp(qdf_dev->dev, PLD_TRIGGER_NEGATIVE_EDGE,
126 &lpass_ts);
127
128 qdf_mutex_acquire(&vdev_priv->ftm_time_sync_mutex);
129
130 if (vdev_priv->num_reads) {
131 vdev_priv->num_reads--;
132 qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex);
133 qdf_delayed_work_start(&vdev_priv->ftm_time_sync_work,
134 vdev_priv->time_sync_interval);
135 } else {
136 qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex);
137 }
138
139 if (vdev_priv->valid) {
140 status = vdev_priv->tx_ops.ftm_time_sync_send_qtime(
141 psoc, vdev_id, lpass_ts);
142 if (status != QDF_STATUS_SUCCESS)
143 ftm_time_sync_err("send_ftm_time_sync_qtime failed %d",
144 status);
145 vdev_priv->valid = false;
146 } else {
147 vdev_priv->valid = true;
148 }
149 }
150
151 QDF_STATUS
ftm_time_sync_vdev_create_notification(struct wlan_objmgr_vdev * vdev,void * arg)152 ftm_time_sync_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg)
153 {
154 struct ftm_time_sync_vdev_priv *vdev_priv;
155 struct wlan_objmgr_psoc *psoc;
156 QDF_STATUS status;
157
158 psoc = wlan_vdev_get_psoc(vdev);
159 if (!psoc) {
160 ftm_time_sync_err("Failed to get psoc");
161 return QDF_STATUS_E_INVAL;
162 }
163
164 if (!ftm_time_sync_is_enable(psoc))
165 return QDF_STATUS_SUCCESS;
166
167 vdev_priv = qdf_mem_malloc(sizeof(*vdev_priv));
168 if (!vdev_priv) {
169 status = QDF_STATUS_E_NOMEM;
170 goto exit;
171 }
172
173 status = wlan_objmgr_vdev_component_obj_attach(
174 vdev, WLAN_UMAC_COMP_FTM_TIME_SYNC,
175 (void *)vdev_priv, QDF_STATUS_SUCCESS);
176 if (QDF_IS_STATUS_ERROR(status)) {
177 ftm_time_sync_err("Failed to attach priv with vdev");
178 goto free_vdev_priv;
179 }
180
181 vdev_priv->vdev = vdev;
182 status = qdf_delayed_work_create(&vdev_priv->ftm_time_sync_work,
183 ftm_time_sync_work_handler, vdev_priv);
184 if (QDF_IS_STATUS_ERROR(status)) {
185 ftm_time_sync_err("Failed to create ftm time sync work\n");
186 goto free_vdev_priv;
187 }
188
189 qdf_mutex_create(&vdev_priv->ftm_time_sync_mutex);
190
191 target_if_ftm_time_sync_register_tx_ops(&vdev_priv->tx_ops);
192 target_if_ftm_time_sync_register_rx_ops(&vdev_priv->rx_ops);
193
194 vdev_priv->rx_ops.ftm_time_sync_register_start_stop(psoc);
195 vdev_priv->rx_ops.ftm_time_sync_regiser_initiator_target_offset(psoc);
196
197 vdev_priv->valid = true;
198
199 goto exit;
200
201 free_vdev_priv:
202 qdf_mem_free(vdev_priv);
203 status = QDF_STATUS_E_INVAL;
204 exit:
205 return status;
206 }
207
208 static QDF_STATUS
ftm_time_sync_deregister_wmi_events(struct wlan_objmgr_vdev * vdev)209 ftm_time_sync_deregister_wmi_events(struct wlan_objmgr_vdev *vdev)
210 {
211 struct wlan_objmgr_psoc *psoc;
212 QDF_STATUS status;
213
214 psoc = wlan_vdev_get_psoc(vdev);
215 if (!psoc) {
216 ftm_time_sync_err("Failed to get psoc");
217 return QDF_STATUS_E_INVAL;
218 }
219
220 status = target_if_ftm_time_sync_unregister_ev_handlers(psoc);
221 return status;
222 }
223
224 QDF_STATUS
ftm_time_sync_vdev_destroy_notification(struct wlan_objmgr_vdev * vdev,void * arg)225 ftm_time_sync_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev,
226 void *arg)
227
228 {
229 struct ftm_time_sync_vdev_priv *vdev_priv = NULL;
230 struct wlan_objmgr_psoc *psoc;
231 QDF_STATUS status = QDF_STATUS_E_FAILURE;
232
233 psoc = wlan_vdev_get_psoc(vdev);
234 if (!psoc) {
235 ftm_time_sync_err("Failed to get psoc");
236 return QDF_STATUS_E_INVAL;
237 }
238
239 if (!ftm_time_sync_is_enable(psoc))
240 return QDF_STATUS_SUCCESS;
241
242 vdev_priv = ftm_time_sync_vdev_get_priv(vdev);
243 if (!vdev_priv) {
244 ftm_time_sync_err("vdev priv is NULL");
245 goto exit;
246 }
247
248 qdf_mutex_destroy(&vdev_priv->ftm_time_sync_mutex);
249 qdf_delayed_work_destroy(&vdev_priv->ftm_time_sync_work);
250
251 ftm_time_sync_deregister_wmi_events(vdev);
252
253 status = wlan_objmgr_vdev_component_obj_detach(
254 vdev, WLAN_UMAC_COMP_FTM_TIME_SYNC,
255 (void *)vdev_priv);
256 if (QDF_IS_STATUS_ERROR(status))
257 ftm_time_sync_err("Failed to detach priv with vdev");
258
259 qdf_mem_free(vdev_priv);
260 vdev_priv = NULL;
261
262 exit:
263 return status;
264 }
265
266 static void
ftm_time_sync_cfg_init(struct ftm_time_sync_psoc_priv * psoc_priv)267 ftm_time_sync_cfg_init(struct ftm_time_sync_psoc_priv *psoc_priv)
268 {
269 psoc_priv->cfg_param.enable = cfg_get(psoc_priv->psoc,
270 CFG_ENABLE_TIME_SYNC_FTM);
271 psoc_priv->cfg_param.role = cfg_get(psoc_priv->psoc,
272 CFG_TIME_SYNC_FTM_ROLE);
273 psoc_priv->cfg_param.mode = cfg_get(psoc_priv->psoc,
274 CFG_TIME_SYNC_FTM_MODE);
275 }
276
277 QDF_STATUS
ftm_time_sync_psoc_create_notification(struct wlan_objmgr_psoc * psoc,void * arg)278 ftm_time_sync_psoc_create_notification(struct wlan_objmgr_psoc *psoc, void *arg)
279 {
280 struct ftm_time_sync_psoc_priv *psoc_priv;
281 QDF_STATUS status;
282
283 psoc_priv = qdf_mem_malloc(sizeof(*psoc_priv));
284 if (!psoc_priv)
285 return QDF_STATUS_E_NOMEM;
286
287 status = wlan_objmgr_psoc_component_obj_attach(
288 psoc, WLAN_UMAC_COMP_FTM_TIME_SYNC,
289 psoc_priv, QDF_STATUS_SUCCESS);
290 if (QDF_IS_STATUS_ERROR(status)) {
291 ftm_time_sync_err("Failed to attach psoc component obj");
292 goto free_psoc_priv;
293 }
294
295 psoc_priv->psoc = psoc;
296 ftm_time_sync_cfg_init(psoc_priv);
297
298 return status;
299
300 free_psoc_priv:
301 qdf_mem_free(psoc_priv);
302 return status;
303 }
304
305 QDF_STATUS
ftm_time_sync_psoc_destroy_notification(struct wlan_objmgr_psoc * psoc,void * arg)306 ftm_time_sync_psoc_destroy_notification(struct wlan_objmgr_psoc *psoc,
307 void *arg)
308 {
309 struct ftm_time_sync_psoc_priv *psoc_priv;
310 QDF_STATUS status;
311
312 psoc_priv = ftm_time_sync_psoc_get_priv(psoc);
313 if (!psoc_priv) {
314 ftm_time_sync_err("psoc priv is NULL");
315 return QDF_STATUS_E_FAILURE;
316 }
317
318 status = wlan_objmgr_psoc_component_obj_detach(
319 psoc, WLAN_UMAC_COMP_FTM_TIME_SYNC,
320 psoc_priv);
321 if (QDF_IS_STATUS_ERROR(status)) {
322 ftm_time_sync_err("Failed to detach psoc component obj");
323 return status;
324 }
325
326 qdf_mem_free(psoc_priv);
327 return status;
328 }
329
ftm_time_sync_send_trigger(struct wlan_objmgr_vdev * vdev)330 QDF_STATUS ftm_time_sync_send_trigger(struct wlan_objmgr_vdev *vdev)
331 {
332 struct ftm_time_sync_vdev_priv *vdev_priv;
333 struct wlan_objmgr_psoc *psoc;
334 enum ftm_time_sync_mode mode;
335 uint8_t vdev_id;
336 QDF_STATUS status;
337
338 psoc = wlan_vdev_get_psoc(vdev);
339 if (!psoc) {
340 ftm_time_sync_err("Failed to get psoc");
341 return QDF_STATUS_E_INVAL;
342 }
343
344 vdev_priv = ftm_time_sync_vdev_get_priv(vdev);
345 if (!vdev_priv) {
346 ftm_time_sync_err("Failed to get ftm time sync vdev_priv");
347 return QDF_STATUS_E_INVAL;
348 }
349
350 vdev_id = wlan_vdev_get_id(vdev_priv->vdev);
351 mode = ftm_time_sync_get_mode(psoc);
352
353 status = vdev_priv->tx_ops.ftm_time_sync_send_trigger(psoc,
354 vdev_id, mode);
355 if (QDF_IS_STATUS_ERROR(status))
356 ftm_time_sync_err("send_ftm_time_sync_trigger failed %d",
357 status);
358
359 return QDF_STATUS_SUCCESS;
360 }
361
ftm_time_sync_stop(struct wlan_objmgr_vdev * vdev)362 QDF_STATUS ftm_time_sync_stop(struct wlan_objmgr_vdev *vdev)
363 {
364 struct ftm_time_sync_vdev_priv *vdev_priv;
365 int iter;
366
367 vdev_priv = ftm_time_sync_vdev_get_priv(vdev);
368 if (!vdev_priv) {
369 ftm_time_sync_err("Failed to get ftm time sync vdev_priv");
370 return QDF_STATUS_E_INVAL;
371 }
372
373 qdf_delayed_work_stop_sync(&vdev_priv->ftm_time_sync_work);
374
375 for (iter = 0; iter < vdev_priv->num_qtime_pair; iter++) {
376 vdev_priv->ftm_ts_priv.time_pair[iter].qtime_initiator = 0;
377 vdev_priv->ftm_ts_priv.time_pair[iter].qtime_target = 0;
378 }
379
380 vdev_priv->num_qtime_pair = 0;
381
382 return QDF_STATUS_SUCCESS;
383 }
384
ftm_time_sync_show(struct wlan_objmgr_vdev * vdev,char * buf)385 ssize_t ftm_time_sync_show(struct wlan_objmgr_vdev *vdev, char *buf)
386 {
387 struct ftm_time_sync_vdev_priv *vdev_priv;
388 uint64_t q_initiator, q_target;
389 ssize_t size = 0;
390 int iter;
391
392 vdev_priv = ftm_time_sync_vdev_get_priv(vdev);
393 if (!vdev_priv) {
394 ftm_time_sync_debug("Failed to get ftm time sync vdev_priv");
395 return 0;
396 }
397
398 size = qdf_scnprintf(buf, PAGE_SIZE,
399 "%s " QDF_MAC_ADDR_FMT "\n", "BSSID",
400 QDF_MAC_ADDR_REF(vdev_priv->bssid.bytes));
401
402 for (iter = 0; iter < vdev_priv->num_qtime_pair; iter++) {
403 q_initiator = vdev_priv->ftm_ts_priv.time_pair[iter].qtime_initiator;
404 q_target = vdev_priv->ftm_ts_priv.time_pair[iter].qtime_target;
405
406 size += qdf_scnprintf(buf + size, PAGE_SIZE - size,
407 "%s %llu %s %llu %s %lld\n",
408
409 "Qtime_initiator", q_initiator, "Qtime_target",
410 q_target, "Offset", q_target > q_initiator ?
411 q_target - q_initiator : q_initiator - q_target);
412 }
413 return size;
414 }
415
ftm_time_sync_update_bssid(struct wlan_objmgr_vdev * vdev,struct qdf_mac_addr bssid)416 void ftm_time_sync_update_bssid(struct wlan_objmgr_vdev *vdev,
417 struct qdf_mac_addr bssid)
418 {
419 struct ftm_time_sync_vdev_priv *vdev_priv;
420
421 vdev_priv = ftm_time_sync_vdev_get_priv(vdev);
422 if (!vdev_priv) {
423 ftm_time_sync_debug("Failed to get ftm time sync vdev_priv");
424 return;
425 }
426
427 vdev_priv->bssid = bssid;
428 }
429